# Clean succession

> handoff 작성, placement 검증 spawn, successor 검증, predecessor retire, revival 측정, lineage 스키마 필드.

- 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/master-lifecycle.md`
- `src/master_runtime/core/succession.py`
- `src/master_runtime/core/lineage.py`
- `src/master_runtime/core/recovery.py`
- `master-ops/docs/runbooks/succession-boot-card.md`
- `master-ops/docs/charter/06-succession.md`
- `scripts/master-succeed`
- `tests/test_succession.py`

---

---
title: "Clean succession"
description: "handoff 작성, placement 검증 spawn, successor 검증, predecessor retire, revival 측정, lineage 스키마 필드."
---

Clean succession은 `scripts/master-succeed`와 `master_runtime.core.succession` / `lineage` / `recovery`가 구현하는 **명시적 마스터 세대 전환**이다. 자동 승계는 없고, 선행 마스터가 thin handoff를 만든 뒤 placement가 검증된 후계자를 spawn하고, 후계자가 recovery 보고서로 검증된 다음에야 predecessor를 측정 기반 retire하며, 결과는 append-only lineage에만 남긴다. 사고 복구(같은 세션 resume)는 succession이 아니다.

## 한눈에 보는 흐름

```text
detect (IMMEDIATE only auto-acts as policy)
  → promotion audit (durable SSOT)
  → handoff (thin markdown from JSON spec)
  → spawn (placement + handle liveness fail-closed)
  → successor boot / placement three-set / Role State
  → verify-successor (recovery report PASS|PARTIAL|FAILED)
  → retirement handshake → retire --execute (three disappearances)
  → revival scan (lineage session ids in process argv)
  → append lineage (observability only)
```

| 단계 | 공개 CLI | 핵심 모듈 | 판정 단위 |
|------|----------|-----------|-----------|
| 트리거 | `master-succeed detect` | `detect_trigger` | `IMMEDIATE` / `ADVISORY` / `NONE` |
| handoff | `master-succeed handoff` | `build_handoff` | thin markdown 섹션 |
| spawn | `master-succeed spawn` | `spawn_successor` | worktree·placement·handle liveness |
| 중복 | `master-succeed check-duplicates` | `detect_duplicate_instances` | same-marker 세션 목록 |
| 후계 검증 | `master-succeed verify-successor` | `verify_successor` | recovery step 상태 |
| retire | `master-succeed retire` | `retire_predecessor` | pane·process·tty 소멸 |
| lineage | (런타임 호출) | `lineage.append_entry` | 고정 스키마 섹션 |

운영 절차 원문은 `master-ops/docs/charter/06-succession.md`와 `master-ops/docs/runbooks/succession-boot-card.md`이다. CLI 플래그·exit 코드 표는 [master-succeed 레퍼런스](/succession-cli-reference)를 본다.

## 전제와 불변식

- **트리거는 명시적 사용자 지시만 실행 경로를 연다.** 컨텍스트 비율 ≥ 0.60 또는 마일스톤은 `ADVISORY`이며 메시지에 auto-succession 금지 문구를 붙인다.
- **정상 운영은 continue-and-compact.** 수락 지식·활성 트랙·열린 결정은 이슈 트래커/Git에 먼저 promote한다. handoff는 얇은 스냅샷이지 SSOT가 아니다.
- **Placement three-set** (spawn 후 후계자가 측정):
  1. host pane/worktree selector가 의도 workspace와 일치
  2. process cwd가 workspace root(`{{WORKSPACE_ROOT}}`) 아래
  3. session artifact/log path가 기대 workspace/session namespace
- **UI 제목·상태줄은 placement 증거가 아니다.**
- **Lineage는 관측 메타데이터만.** 부트스트랩 입력·런타임 결정에 쓰지 않는다.
- **사고 복구 ≠ succession.** 프로세스 사망·host 재시작·stale handle·우발 pane 종료는 먼저 동일 세션 resume을 시도하고, 라이브 중복 프로세스가 없음을 증명한다.

## 절차

<Steps>
<Step title="Promotion audit">
수락 지식, 활성/열린 트랙, 미해결 acceptance 증거를 durable store에 올린다. 부트 카드 규칙: promotion audit 없이 successor를 spawn하지 않는다.
</Step>
<Step title="트리거 분류 (선택)">
```bash
scripts/master-succeed detect "succession now" --context-ratio 0.65 --json
```
`IMMEDIATE` 마커: `succession now`, `handoff to successor`, `승계해줘`, `다음 마스터로 넘기자`, `승계 진행해`.
</Step>
<Step title="Thin handoff 작성">
구조화 JSON spec에서 handoff markdown을 생성한다.

```bash
scripts/master-succeed handoff --spec ./ops/handoff-spec.json --json
```

필수 섹션: `## Role State`, `## Current Objective`, `## Active/Open Tracks`, `## Accepted Artifacts`, `## Deferred Work`, `## Open Questions`, `## Recommended Next Role`, `## Observed Baseline`. Role State는 freeze되어 현재 역할만 유지하고 나머지는 lock된다 (`unlock: explicit user instruction only`).
</Step>
<Step title="Placement 검증 spawn">
```bash
scripts/master-succeed spawn \
  --workspace-selector "id:folder:<uuid>" \
  --kickoff-file ./ops/kickoff.md \
  --root . \
  --model example-model \
  --title "Successor master boot" \
  --expected-placement "folder:<uuid>" \
  --json \
  --dry-run
```
비 dry-run 시 `orca terminal create` 후 worktreeId가 selector(및 `--expected-placement`)와 일치해야 한다. 불일치 시 생성 terminal을 close하고 fail-closed한다. 보고 handle은 스냅샷 이후 **live·new·connected** 여야 하며, 그렇지 않으면 동일 worktree·동일 title 후보가 정확히 1개일 때만 `MATCH_REISSUED`로 채택한다.
</Step>
<Step title="Successor boot와 검증">
후계자는 Role State 선언, 측정 model field, placement three-set, (지원 시) coordinator Run 바인딩을 수행한다. recovery 보고서 형태로:

```bash
scripts/master-succeed verify-successor --report ./ops/recovery-report.json --json
```

`verify_successor`는 recovery step 중 하나라도 `MISS`면 `FAILED`. 그 외 step `6`=OK(트랙 낭독), `2-3`=OK/없음(baseline), `5`=OK(모니터) 세 체크가 모두 있으면 `PASS`, 일부면 `PARTIAL`.
</Step>
<Step title="Retirement handshake 후 retire">
Freeze는 retirement가 아니다. 합의된 FIN/ACK 핸드셰이크 후 후계자가 close한다. 기본은 dry-run; 실제 close는 `--execute`.

```bash
scripts/master-succeed retire \
  --self-handle <successor-handle> \
  --target-handle <predecessor-handle> \
  --target-pid <measured-pid> \
  --target-tty <measured-tty> \
  --json \
  --execute
```

`CLOSED`는 **pane·process·tty 세 소멸이 모두 `measured`**일 때만. process/tty를 건너뛰면 `CLOSED_PARTIAL`. 생존은 `REFUSED`. self-handle 매치·후보 0/2+는 거부.
</Step>
<Step title="Revival 측정과 lineage 기록">
부트 시 및 소유자 보고 시 `docs/lineage/MASTER-LINEAGE.md`에 기록된 session id를 **프로세스 argv**에서 스캔한다(CLI resume 플래그가 아니라 session id가 이식 키). 히트 시 활동 복구 → 미응답 지시 흡수 → 프로세스 종료 → tty chain hang-up → 소멸 재측정. 검증 후 lineage 항목을 append한다.
</Step>
</Steps>

## Trigger 분류

| status | 조건 | 정책 의미 |
|--------|------|-----------|
| `IMMEDIATE` | 명시 마커 문자열 포함 | 사용자 지시로 succession 절차 진행 가능 |
| `ADVISORY` | `context_ratio >= 0.60` 또는 non-empty `milestone` | 제안만; 자동 spawn 금지 |
| `NONE` | 그 외 | 트리거 없음 |

`detect`는 분류만 하며 spawn을 호출하지 않는다.

## Handoff 스펙

`build_handoff`는 mapping/JSON에서 markdown을 조립한다.

| 입력 키 | 타입 | 용도 |
|---------|------|------|
| `role_state` 또는 `current_role` | RoleState / str | Role Lock 블록 |
| `current_objective` | str | 현재 목표 |
| `active_tracks`, `open_tracks` | list | 활성/열린 트랙 |
| `accepted_artifacts` | list | 수락 산출물 |
| `deferred_work` | list | 보류 작업 |
| `open_questions` | list | 열린 질문 |
| `recommended_next_role` | str | 권장 다음 역할(기본: frozen current) |
| `observed_baseline` | str | 관측 baseline |

Handoff 본문에 `Current Role:` / `Role Lock:` 블록이 있어야 recovery step 1이 Role State를 인식한다.

## Placement 검증 spawn

### 실패·성공 상태

| 결과 | 의미 |
|------|------|
| `DRY_RUN` | create 없이 명령·startup 문자열만 반환 |
| `CREATED` + `verification.result=MATCH` | 보고 handle이 live+new+connected |
| `CREATED` + `MATCH_REISSUED` | handle 재발급; 유일 title 후보 채택, `handle_reissued=true` |

### Exit 코드 (spawn 경로)

| 코드 | 상수 | 조건 |
|------|------|------|
| 20 | `SPAWN_CREATE_ERROR` | `orca terminal create` 실패 |
| 21 | `SPAWN_PARSE_ERROR` | create JSON 파싱/필드 누락 |
| 22 | `SPAWN_WORKTREE_MISMATCH` | 반환 worktreeId ≠ `--workspace-selector` |
| 23 | `SPAWN_CLOSE_ERROR` | mismatch cleanup close 실패 |
| 24 | `SPAWN_HANDLE_STALE` | handle 신뢰 불가, 재발급 후보 ≠ 1 |
| 25 | `SPAWN_LIST_ERROR` | precheck/liveness list 실패 |
| 26 | `SPAWN_PLACEMENT_MISMATCH` | `--expected-placement` 불일치 |

`--expected-placement`는 독립적으로 기대하는 worktree id다. 형식: `id:<repoId>::<path>`, `folder:<uuid>` / `id:folder:<uuid>`. `path:`는 repository worktree에만 매칭된다.

### Agent 기본 모델 (`scripts/master-succeed`)

| `--agent` | 생략 시 기본 `--model` |
|-----------|------------------------|
| `claude`, `claude-code` | `claude-fable-5` |
| `grok`, `grok-build` | `grok-4.5` |
| `codex` | `gpt-5.6-sol` |
| `cursor` / `agy` 등 | 기본값 없음 → `--model` 필수 (exit 2) |

Startup 커맨드는 agent별로 다르며(예: claude `--dangerously-skip-permissions`, grok `--always-approve`, codex는 launch approval 없음, cursor는 `cursor-agent --force --trust`), 미측정 agent는 이름만 executable로 취급하고 approval 플래그를 추측하지 않는다.

### 셀렉터 힌트

수락 형태: full `id:<repoId>::<path>`, folder workspace `id:folder:<uuid>`; `path:`는 resolved directory로 매칭. 마스터 좌석은 multi-repo에서 folder workspace, single-repo에서는 primary worktree다.

## Successor 검증과 recovery 단계

`verify_successor` 입력은 `RecoveryReport` 또는 동일 shape JSON이다. recovery executor(`recover`)는 **파일 쓰기·프로세스 변경 없이** step 0–6을 관측한다.

| step | 내용 | 실패 시 |
|------|------|---------|
| 0 | charter + bootstrap Role State | `MISS` → 이후 fail-closed skip |
| 1 | handoff 존재·Role State 블록 | missing handoff → `MISS` |
| 1-ledger | work ledger active tracks (옵션) | path 없으면 `SKIP` |
| 2-3 | 저장소 git 관측 | dirty 등 `WARN` |
| 4 | miss 수집 + Trace Archive 수동 | 항상 manual note |
| 5 | monitor pgrep 패턴 | 매치 시 재장착 수동 action |
| 6 | successor checklist (트랙 낭독, PID 비교, lineage append) | 항상 `OK` + manual_actions |

체크리스트 고정 문구에는 “Append the succession lineage entry after verification.”가 포함된다.

## Predecessor retire

### 상태 머신

| status | 조건 |
|--------|------|
| `DRY_RUN` | `--execute` 없음; close 미호출 |
| `REFUSED` | 후보 없음/모호, self 매치, close 실패, 소멸 실패(`still_present`) |
| `CLOSED_PARTIAL` | pane `measured`, 생존 없음, process/tty 중 `skipped:*` |
| `CLOSED` | pane·process·tty 모두 `measured` |

### `disappearances` 값

| 키 | 값 |
|----|-----|
| `pane` | `measured` \| `still_present` |
| `process` | `measured` \| `still_present` \| `skipped:…` |
| `tty` | `measured` \| `still_present` \| `skipped:…` |

Folder-workspace pane은 host list에서 `process_id: null`인 경우가 많다. 호출자가 측정한 `--target-pid` / `--target-tty`를 넘겨야 full `CLOSED`가 된다. 도구는 null 레코드에서 pid를 발명하지 않는다.

### Handshake 요약 (운영)

| TCP 비유 | 행위 | 주체 |
|----------|------|------|
| FIN → | 신규 dispatch 중단·flush 요청 | successor |
| ← ACK / half-close | CLOSE_WAIT 규칙 준수·커밋 | predecessor |
| ← FIN | 합의 FIN 한 줄 | predecessor |
| TIME_WAIT | 조용 구간 측정 후 close | successor |
| CLOSED | `retire --execute` + 삼중 소멸 | successor |
| RST | 동의 없는 abortive close | 소유자 승인 필요 |

CLOSE_WAIT에 포함되는 약속: 신규 dispatch 금지, peer-mailbox 이중 drain 또는 무ack, orchestration 추가 송신 없음, 미커밋 상태 커밋 또는 경로 보고, 소유 worker·트랙 목록, 합의 FIN 한 줄. FIN은 idle prompt에 보내고 pane read로 소비를 검증한다.

CLOSED 전 predecessor scratchpad를 durable(비-git) 위치로 스윕하고 trunk와 diff 판정을 남긴다.

## Revival 측정

동결 세션은 agent CLI가 돌아가는 어떤 단말에서도 영구 resume 가능하다. 측정 사건(2026-08-03): 모바일 resume으로 retired master 네 개가 동시에 부활. 대응:

1. lineage에 적힌 session id를 실행 중 agent 프로세스 argv에서 스캔
2. 히트 세션 자체 기록에서 freeze 이후 활동 확인
3. 미응답 소유자 지시를 현 마스터로 회수
4. agent 프로세스 종료 → hosting terminal chain hang-up → tty 소멸 확인
5. 다른 자식이 있는 셸은 자식을 먼저 측정

Revival 소멸도 retirement와 동일한 삼중 측정 기준을 따른다. handoff 텍스트의 “predecessor gone”과 런타임 상태는 별개로 검사한다.

## Lineage 스키마

`master_runtime.core.lineage.append_entry(path, entry)`는 markdown ledger에 세대 섹션을 append-only로 추가한다. 기본 경로 관례: `docs/lineage/MASTER-LINEAGE.md`.

### 필수 필드

| 필드 | 타입 | 제약 |
|------|------|------|
| `generation` | int | ≥ 0; 기존 Generation 마커와 중복 불가 |
| `parent_session` | str | 선행 세션 식별 |
| `successor_session` | str | 후계 세션 식별 |
| `timestamp` | str | 승계 시각 서술 |
| `inherited_role` | str | 상속 역할(승계가 역할을 바꾸지 않음이 일반) |
| `succession_reason` | str | 사유 |
| `recovery_sources` | str | 복구 소스 목록 서술 |
| `inherited_open_tracks` | str | 상속 트랙 요약 |
| `verification` | str | `PASS` \| `PARTIAL` \| `FAILED` only |
| `repeated_question_count` | int | ≥ 0 |
| `reopened_decision_count` | int | ≥ 0 |
| `context_loss_summary` | str | 컨텍스트 손실 요약 |
| `predecessor_retirement_verified` | str | retirement 검증 서술 |
| `notes` | str | 선택 |

렌더 헤더: `## Gen {generation} — {timestamp}`. 검증 실패 시 파일 바이트 불변; write 후 prefix 불일치 시 `LineageAppendError`와 원본 복원.

Lineage는 회고·승계 품질 지표용이다. 실행 메모리로 쓰지 않는다.

## 검증 신호

| 신호 | 기대 |
|------|------|
| `detect … --json` | `status` IMMEDIATE/ADVISORY/NONE |
| `handoff --json` | `handoff`에 Role State 포함 8섹션 |
| `spawn --dry-run --json` | `status=DRY_RUN`, create command·startup_command |
| spawn success | `status=CREATED`, `verified=true`, `MATCH` 또는 `MATCH_REISSUED` |
| placement 실패 | stderr + exit **26**, 생성 terminal close 시도 |
| `verify-successor` | `PASS` / `PARTIAL` / `FAILED` |
| `retire` without `--execute` | `DRY_RUN` |
| full retire | `CLOSED`, disappearances 세 키 모두 `measured` |
| partial measure | `CLOSED_PARTIAL` (skip을 pass로 읽지 말 것) |
| revival | lineage session id 프로세스 없음 + tty 소멸 |
| lineage append | 새 `## Gen N` 섹션, 기존 prefix 바이트 동일 |

## 실패 모드와 복구

| 증상 | 원인 | 조치 |
|------|------|------|
| `SPAWN_PLACEMENT_MISMATCH` (26) | create 위치 ≠ expected | selector·expected-placement 재측정, unmanaged terminal reconcile 후 재시도 |
| `SPAWN_HANDLE_STALE` (24) | handle 재사용/지연 | `orca terminal list`로 정리, title 유일성 확보 |
| retire `REFUSED` ambiguous | 후보 2+ | `--target-handle` / pty / session-id로 단일화 |
| retire self match | self_handle = 후보 | 측정 handle 교환 확인 |
| `CLOSED_PARTIAL` | pid/tty 미공급 | 라이브 측정 후 `--target-pid`/`--target-tty` 재실행 |
| process/tty still_present | close 반환만 신뢰 | 측정 재시도; RST는 소유자 승인 |
| verify FAILED | recovery MISS | charter/handoff 복구 후 recover 재실행 |
| dual revival | 모바일/원격 resume | session id 스캔 → 삼중 소멸 |
| model drift at audit | mid-session model 변경 | `model-drift-audit` 전체 walk; exit 2는 undecidable ≠ pass |

추가 트러블슈팅 표는 [Troubleshooting](/troubleshooting), 방어 장치 목록은 [방어 인벤토리](/defense-inventory)를 본다.

## CLI 요약

```bash
scripts/master-succeed detect TEXT [--context-ratio F] [--json]
scripts/master-succeed handoff --spec PATH [--json]
scripts/master-succeed verify-successor --report PATH [--json]
scripts/master-succeed check-duplicates --self-handle H --marker M [--json]
scripts/master-succeed retire --self-handle H [--expected S]
  [--target-handle H] [--target-pty-id ID] [--target-session-id ID]
  [--target-pid PID] [--target-tty TTY] [--execute] [--json]
scripts/master-succeed spawn --workspace-selector SEL
  (--kickoff-text T | --kickoff-file F) --root PATH --title TITLE
  [--model M] [--agent A] [--expected-placement P] [--dry-run] [--json]
```

공통: 성공 시 JSON payload를 stdout에 출력(기본 pretty, `--json`은 compact). `SuccessionError`는 stderr 메시지 + `exit_code`(기본 2, spawn 전용 20–26).

## Related pages

<CardGroup cols={2}>
  <Card title="마스터 라이프사이클" href="/master-lifecycle">
    founding spawn → boot → steady state → succession → lineage 루프
  </Card>
  <Card title="master-succeed 레퍼런스" href="/succession-cli-reference">
    하위 명령·플래그·exit 코드·SPAWN_PLACEMENT_MISMATCH
  </Card>
  <Card title="Orca 객체 모델" href="/orca-object-model">
    folder workspace·worktree·terminal selector 형식
  </Card>
  <Card title="프로그레시브 온보딩" href="/onboarding">
    Generation 1 founding spawn과 템플릿 경계
  </Card>
  <Card title="방어 인벤토리" href="/defense-inventory">
    placement·duplicate·revival 가드 표
  </Card>
  <Card title="Troubleshooting" href="/troubleshooting">
    placement mismatch, seat 중복, revival 복구 프로브
  </Card>
</CardGroup>
