# 인스턴스 설정

> instance-runtime·model-tier-policy 작성, env 우선순위, transcript glob, master host runtime, 티어×fan-out 캡.

- 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

- `config/instance-runtime.example.json`
- `config/model-tier-policy.example.json`
- `src/master_runtime/core/instance_runtime_config.py`
- `src/master_runtime/core/dispatch_gate.py`
- `master-ops/model-tier-policy.json`
- `scripts/model-identity-probe`
- `tests/test_instance_runtime_config.py`

---

---
title: "인스턴스 설정"
description: "instance-runtime·model-tier-policy 작성, env 우선순위, transcript glob, master host runtime, 티어×fan-out 캡."
---

인스턴스 소유 런타임 사실은 `config/instance-runtime.json`과 `config/model-tier-policy.json`에 기록되며, 템플릿은 각각 `config/instance-runtime.example.json`·`config/model-tier-policy.example.json`만 제공한다. 소비자는 환경 변수 → 인스턴스 파일 → 정직한 unconfigured(또는 티어 정책 템플릿 폴백) 순으로 값을 해석하고, 호스트·모델 식별자를 코드에 구워 넣지 않는다. 채워진 파일은 `.gitignore` 대상이며 git에 커밋하지 않는다.

## 인스턴스 파일 경계

| 파일 | 역할 | 기본 경로 해석 |
| --- | --- | --- |
| `config/instance-runtime.json` | 마스터 호스트 CLI, transcript glob, 선택적 primary product | `INSTANCE_RUNTIME_CONFIG` → `<repo>/config/instance-runtime.json` |
| `config/model-tier-policy.json` | 티어×fan-out 정책 (게이트 소비) | `DISPATCH_TIER_POLICY` → 인스턴스 파일(존재 시) → `master-ops/model-tier-policy.json` |
| `config/instance-runtime.example.json` | 스키마·문서용 예시 (커밋됨) | 복사 원본만 |
| `config/model-tier-policy.example.json` | v2 정책 예시 (커밋됨) | 복사 원본만 |

<Warning>
채워진 `config/instance-runtime.json` / `config/model-tier-policy.json`은 인스턴스 소유다. 예제 파일을 저장소에 덮어쓰거나 커밋하지 않는다. onboarding preflight가 없을 때 `cp …example…` 한 번 후 로컬에서만 채운다.
</Warning>

```text
config/
  instance-runtime.example.json   # 템플릿 (커밋)
  instance-runtime.json           # 인스턴스 작성 (gitignore)
  model-tier-policy.example.json  # 템플릿 (커밋)
  model-tier-policy.json          # 인스턴스 작성 (gitignore)
master-ops/
  model-tier-policy.json          # 게이트 템플릿 폴백 (커밋)
```

로더는 `src/master_runtime/core/instance_runtime_config.py`와 `src/master_runtime/core/dispatch_gate.py`의 `_default_tier_policy_path`다. 기본 경로 계산은 `Path.cwd()`가 아니라 모듈 기준 repo root를 쓰므로, 다른 디렉터리에서 프로브해도 `config/`를 찾는다.

## instance-runtime 작성

### 스키마

| 키 | 타입 | 필수 | 의미 |
| --- | --- | --- | --- |
| `master_host_runtime` | string \| null | 마스터/프로브 시 필요 | 마스터 세션을 호스팅하는 agent CLI 이름 (`claude`, `codex`, `grok` 등) |
| `transcript_globs` | object string→string | 프로브 시 런타임별 필요 | 런타임 이름 → 세션 JSONL 파일시스템 glob |
| `product_repo` | string \| null | 선택 | primary product 저장소 절대 경로; 멀티 제품·미지정 시 omit/null |
| `_docs` 등 `_` 접두 키 | any | 무시 | 문서/주석; 로더가 제거 |

`transcript_globs` 키는 **런타임(agent CLI) 이름**이다. 머신 별명·호스트 닉네임이 아니다. 최소한 `master_host_runtime`에 해당하는 엔트리가 측정되거나 소유자가 명시해야 한다.

### 작성 절차

<Steps>
  <Step title="예제 복사 (없을 때만)">
```console
$ cd "{{RUNTIME_ROOT}}"
$ test -f config/instance-runtime.json || cp config/instance-runtime.example.json config/instance-runtime.json
```
  </Step>
  <Step title="master_host_runtime 설정">
preflight/측정으로 확인된 agent CLI 이름을 쓴다. 측정값과 소유자 기대가 다르면 확인 후 기록한다. 측정이 없으면 추측하지 않는다.
  </Step>
  <Step title="transcript_globs 측정·기록">
각 프로브 대상 런타임에 대해 이 머신의 세션 JSONL 트리를 측정해 glob을 넣는다. 다른 워크스페이스 경로를 그대로 붙여 넣지 않는다.
  </Step>
  <Step title="product_repo (선택)">
소유자가 primary product를 확인한 경우에만 절대 경로를 쓴다. 폴더 레이아웃만으로 추측하지 않는다.
  </Step>
</Steps>

예제 형태:

```json
{
  "master_host_runtime": "claude",
  "transcript_globs": {
    "claude": "~/.claude/projects/-Users-example-workspace/*.jsonl",
    "codex": "~/.codex/sessions/**/*.jsonl",
    "grok": "~/.grok/sessions/**/*.jsonl"
  },
  "product_repo": "/absolute/path/to/primary-product-repo"
}
```

### 환경 변수 우선순위

모든 값의 공통 규칙:

1. 환경 오버라이드  
2. 인스턴스 설정 파일  
3. 정직한 unconfigured (`InstanceRuntimeConfigError`) — 베이크된 기본값 없음  

| 환경 변수 | 파일 키 | 비고 |
| --- | --- | --- |
| `INSTANCE_RUNTIME_CONFIG` | (경로 자체) | 설정 파일 위치 오버라이드 |
| `MOGUI_MASTER_HOST_RUNTIME` | `master_host_runtime` | 1순위 |
| `MASTER_HOST_RUNTIME` | `master_host_runtime` | 일부 래퍼용 대체 이름; `MOGUI_*` 다음 |
| `MOGUI_TRANSCRIPT_GLOB` | `transcript_globs.<runtime>` | **런타임 비종속** 단일 glob; 활성 프로브 한 번에 적용 |
| `MOGUI_PRODUCT_REPO` | `product_repo` | — |

`require_*` 헬퍼:

- `require_master_host_runtime()` — 비어 있으면 에러  
- `require_transcript_glob(runtime?)` — env glob이 있으면 즉시 반환; 없으면 `transcript_globs[name]`  
- `require_product_repo()` — 비어 있으면 에러  

파일 부재는 로드 오류가 아니다. 값이 env로도 없으면 `require_*`가 unconfigured를 낸다. 잘못된 타입(예: `master_host_runtime`이 배열)은 hard error다. JSON 파싱 실패도 `InstanceRuntimeConfigError`다.

### Transcript glob과 model-identity-probe

`scripts/model-identity-probe`는 세션 JSONL에서 최근 assistant `model` 필드를 읽는다. 경로 해석 순서:

1. `--transcript` (명시 경로)  
2. `MOGUI_TRANSCRIPT_GLOB` (최신 mtime 매치)  
3. 인스턴스 설정: `--runtime` 또는 `master_host_runtime` → `transcript_globs`  
4. unconfigured → exit `2`, `MODEL-PROBE DRIFT: unconfigured …`

추가 플래그/환경:

| 입력 | 기본 | 효과 |
| --- | --- | --- |
| `--expect` / `MODEL_IDENTITY_EXPECT` | 없음 | 있으면 최근 N개 모델이 전부 일치해야 OK; 없으면 INFO만, exit 0 |
| `--limit` | `10` | 최근 assistant 모델 개수; `<1`이면 exit 2 |
| `--config` | `INSTANCE_RUNTIME_CONFIG` 또는 `config/instance-runtime.json` | 설정 경로 |
| `--runtime` | `master_host_runtime` | glob 키 선택 |

성공/실패 신호:

- `MODEL-PROBE OK <model> N/N` — exit 0  
- `MODEL-PROBE INFO … nothing asserted` — expect 없음, exit 0  
- `MODEL-PROBE DRIFT: …` — exit 2 (불일치·transcript 오류·unconfigured)

모델 이름은 코드에 하드코딩되지 않는다. expect는 호출자/환경이 공급한다.

## model-tier-policy 작성

### 해석 순서 (dispatch gate)

`dispatch_gate._default_tier_policy_path`:

1. `DISPATCH_TIER_POLICY`  
2. `config/model-tier-policy.json` (파일 존재 시)  
3. `master-ops/model-tier-policy.json` (템플릿 폴백)  

CLI `--tier-policy`는 이 헬퍼 위에 있다 (`DispatchGateConfig.tier_policy_path` 직접 설정).

### 스키마 (version 2 — 게이트 소비 필드)

| 키 | 타입 | 필수 | 의미 |
| --- | --- | --- | --- |
| `version` | int | 예 (`2`) | v2 = 티어×fan-out; v1은 identity allow/deny 레거시 |
| `tiers` | object string→string[] | 예 (비어 있지 않은 객체) | 티어 이름 → model id 목록; 목록에 없는 id → 예약 티어 `unknown` |
| `fanout_caps` | object string→int | 예 (객체; 키는 선택) | 티어별 rolling window 안 agent 수 상한; **키 없음 = uncapped** (`top`·`unknown` 포함) |
| `window_seconds` | int | 기본 `86400` | fan-out 카운트 창(초); 양수 정수 |
| `agents` | array | 게이트 무시 | 측정/수동 인벤토리 (사람·재측정용) |
| `consent` | string | 게이트 무시 | `yes` \| `no` \| `manual-only` 등 온보딩 기록 |
| `_docs` / `_notes` | any | 무시 | 문서 |

제약 (파서):

- 티어 이름 `unknown`은 예약 — `tiers`에 넣을 수 없음  
- 한 model id는 한 티어에만 (casefold 후 중복 금지)  
- `fanout_caps` 키는 존재하는 티어이거나 `unknown`  
- cap 값은 non-negative integer (`bool` 불가)  
- model id는 비어 있지 않은 문자열, 앞뒤 공백 없음; 비교는 casefold  

### 온보딩: agent-inventory consent

Preflight 단계에서 소유자에게 인벤토리 프로브 동의를 묻는다.

| consent | 동작 |
| --- | --- |
| yes | PATH에 있는 후보 CLI 측정; `runtime`/`version`/`model_ids`는 측정값만; 측정 불가 필드는 문자열 `unknown`; 강도 구분이 명확할 때만 `tiers.top` / `tiers.efficient`에 배치 |
| no | 프로브 금지; 소유자가 명시한 런타임·모델만 기록; 빈 티어 리스트 허용 → 미등재 모델은 `unknown` |

```console
$ test -f config/model-tier-policy.json || cp config/model-tier-policy.example.json config/model-tier-policy.json
# version:2, agents[], tiers, fanout_caps, window_seconds, consent 채움
```

모델 id를 추측하지 않는다.

### 티어 × fan-out 캡

```mermaid
flowchart LR
  subgraph inputs [요청]
    M[request.model]
    N[n_agents]
  end
  subgraph policy [ModelTierPolicy v2]
    T[tier_of casefold]
    C[cap_for tier]
    W[window_seconds ledger tally]
  end
  subgraph outcomes [판정]
    OK[OK / ledger]
    CAP[TIER_FANOUT_CAP deny]
    UNK[TIER_UNKNOWN_MODEL warning]
  end
  M --> T
  T --> C
  C -->|cap set and used+n_agents > cap| CAP
  C -->|no key uncapped| OK
  T -->|tier == unknown| UNK
  N --> W
  W --> C
```

동작 요약:

- 모델 → 티어 매핑 후, 해당 티어의 `fanout_caps`가 있으면 ledger 창 안 사용량 + 요청 `n_agents`가 cap을 넘으면 `TIER_FANOUT_CAP` deny  
- cap 키 부재 = uncapped (모든 티어 동일 규칙)  
- 미등재 모델 = `unknown` 티어; 차단이 아니라 경고 `TIER_UNKNOWN_MODEL` + `fanout_caps.unknown`이 있으면 그 캡 적용  
- 템플릿/예제 기본: `fanout_caps.unknown: 8`, `window_seconds: 86400`, **`top` 캡 없음**

### Top-tier: cap이 아닌 소유자 승인

2026-08-05 소유자 지침: top-tier fan-out 숫자 캡을 제거하고, 디스패치마다 소유자에게 묻는다. `master-ops/scripts/dispatch`는 top-tier 모델에 `--top-approved "<reason>"`이 없으면 거부하고, reason을 런 로그에 남긴다. 게이트 정책 파일에서 `fanout_caps.top` 키를 빼 두면 top은 uncapped로 해석된다.

레거시 v1 정책(`worker_allowed` / `worker_denied_tiers` / `unknown_model: deny|warn`)은 그대로 로드된다. 런타임만 올려도 기존 설치의 v1 판정이 바뀌지 않는다.

### 정책 파일 부재·손상

`_load_tier_policy` 실패 시 게이트는 `TIER_POLICY_UNAVAILABLE`로 deny하고 `tier_policy=<path>` 메시지를 붙인다. 정상 결정은 ledger에 `tier_policy_path`와 `tier_policy_sha256`(파일 raw bytes의 sha256)을 기록한다.

## 검증 신호

| 확인 | 기대 |
| --- | --- |
| 인스턴스 파일 존재 | onboarding Verify: `config/instance-runtime.json`에 확인된 `master_host_runtime`; `config/model-tier-policy.json`에 `version: 2` |
| 로드 단위 테스트 | `tests/test_instance_runtime_config.py` — env > file > unconfigured, `_` 키 무시, probe glob 해석 |
| 프로브 | `scripts/model-identity-probe --expect <id>` → `MODEL-PROBE OK` 또는 DRIFT exit 2 |
| 게이트 | `scripts/dispatch-gate check …` — 정책 경로/digest, `TIER_FANOUT_CAP` / `TIER_UNKNOWN_MODEL` / `TIER_POLICY_UNAVAILABLE` |
| git 경계 | `git status`에 채워진 인스턴스 JSON이 스테이징되지 않음 (`.gitignore`) |

```console
$ # env만으로 transcript 프로브 (master_host 없이)
$ MOGUI_TRANSCRIPT_GLOB='~/.claude/projects/.../*.jsonl' \
    python3 scripts/model-identity-probe --expect claude-fable-5
```

## 실패 모드

| 증상 | 원인 | 조치 |
| --- | --- | --- |
| `master_host_runtime is unconfigured` | env·파일 모두 비어 있음 | preflight 후 파일 작성 또는 `MOGUI_MASTER_HOST_RUNTIME` |
| `transcript_glob for runtime '…' is unconfigured` | 해당 런타임 glob 없음 | 측정 후 `transcript_globs` 또는 `MOGUI_TRANSCRIPT_GLOB` |
| `no transcript files matched configured glob` | glob 오타·다른 머신 경로 복사 | 이 호스트에서 세션 경로 재측정 |
| `MODEL-PROBE DRIFT` | expect 불일치 또는 transcript 오류 | succession 검토; expect/모델 드리프트 확인 |
| `TIER_POLICY_UNAVAILABLE` | 정책 경로 없음·JSON 오류·version 오류 | `DISPATCH_TIER_POLICY` 또는 인스턴스/템플릿 파일 복구 |
| `TIER_FANOUT_CAP` | 창 안 agent 합이 cap 초과 | 대기·창 조정·정당한 `tier_override`(ledger됨) |
| `fanout_caps names a tier that does not exist` | 오타 티어 키 | `tiers`에 있는 이름 또는 `unknown`만 사용 |
| 미등재 모델이 항상 막힘 | v1 `unknown_model: deny` 또는 top과 동일 취급 착각 | v2로 전환 시 unlisted → `unknown`+선택 캡; top은 `--top-approved` |

## Next

<CardGroup>
  <Card title="Configuration reference" href="/configuration-reference">
    JSON 키·기본값·`INSTANCE_RUNTIME_CONFIG`·`DISPATCH_TIER_POLICY`·`MOGUI_*` 해석 순서 전체 표.
  </Card>
  <Card title="Supervised dispatch" href="/supervised-dispatch">
    check → dispatch → register, model probe, 완료 채널.
  </Card>
  <Card title="dispatch-gate 레퍼런스" href="/dispatch-gate-reference">
    check·register 플래그, ledger, reason code, 티어 정책 해석.
  </Card>
  <Card title="프로그레시브 온보딩" href="/onboarding">
    preflight에서 인스턴스 파일 작성·consent·Verify 게이트.
  </Card>
  <Card title="Workspace descriptor" href="/workspace-descriptor">
    sibling 인벤토리·`product_repo`와 맞물리는 workspace 경계.
  </Card>
  <Card title="Troubleshooting" href="/troubleshooting">
    MODEL_PROBE_FAILED, preflight BLOCKED, 정책 복구 프로브.
  </Card>
</CardGroup>
