> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nora.my/llms.txt
> Use this file to discover all available pages before exploring further.

# 시뮬레이션

> 개선의 근거 만들기 : 견적, 실행, 폴링, promote

시뮬레이션은 제안된 fix의 **근거를 만드는** 방법입니다. 후보 변경을 큐레이션된 데이터셋에 돌리고, 결과 delta를 측정하고, 좋아 보이면 개선 큐에 promote해서 사람이 승인하게 합니다.

**PAT `simulate` 스코프**로 인증합니다. 시뮬은 **유료**입니다. 데이터셋에 LLM 호출을 돌리고 워크스페이스 LLM 키로 과금됩니다.

## budget은 필수

모든 실행에 `budget`이 **필수**입니다 (기본값 없음, 지출이 새면 안 되니까). 두 가지 모양:

* `budgetUsd: <n>` USD 하드 캡.
* `budgetMinutes: <n>` + `confirmUsdCeiling: <n>` 시간 캡 + SDK가 시작 전 확인할 예상 비용 상한.

SDK엔 사람이 없으므로, `budgetMinutes`만 주고 비용 상한을 안 주면 거절됩니다. 새는 지출을 멈출 방법이 없기 때문입니다.

## Verb

시뮬은 장시간 실행입니다. `run`은 `roundId`를 즉시 돌려주고 폴링합니다.

```ts theme={null}
// 실행 없이 config의 비용 · 시간 견적
const est = await nora.simulations.estimate({ /* config */ });

// 실행 시작, 즉시 반환
const run = await nora.simulations.run("lin_1", {
  kind: "consistency",              // 시뮬 종류
  budgetUsd: 5,                     // 또는: budgetMinutes: 30, confirmUsdCeiling: 5
});
run.roundId;                         // 이걸로 폴링

// 진행 · 결과 폴링
await nora.simulations.get(run.roundId);
await nora.simulations.remaining(run.roundId);   // 남은 작업 수만

// 결과를 재랭킹 (무료, 새 LLM 호출 없음)
await nora.simulations.requery(run.roundId);

// 좋은 결과를 개선 제안으로 promote
await nora.simulations.promote(run.roundId);
```

### `estimate`

LLM 호출은 없습니다. `run`에 넘길 config의 예상 비용과 소요 시간을 서버가 돌려줍니다. 게이팅에 씁니다. "예상이 X 초과면 돌리지 마."

### `run(lineageId, opts)`

시뮬을 시작합니다. `lineageId`는 테스트할 변경 계보를 가리킵니다. `{ roundId }`를 즉시 반환합니다.

### `get(roundId)`

라운드 전체 상태입니다. 진행, 케이스별 판정, 집계 delta, 프로바이더 에러(있으면)를 돌려줍니다. 완료까지 폴링하세요.

### `remaining(roundId)`

남은 케이스 수만 돌려줍니다. `get`보다 가볍고, 진행 바에 적합합니다.

### `requery(roundId)`

같은 케이스 결과를 다른 스코어 config로 재랭킹합니다. **무료**입니다. 새 LLM 호출 없이 저장된 출력에 스코어링만 다시 돌립니다. "도움 됐나?" 답이 스코어 선택에 얼마나 민감한지 볼 때 씁니다.

### `promote(roundId)`

완료된 라운드를 개선 제안으로 등록합니다. [개선 큐](/ko/sdk/improvements)로 흘러 들어가 사람이 승인합니다. 시뮬은 *근거*, 승인이 배포입니다.

## 흔한 패턴

### 견적 → 게이트 → 실행

```ts theme={null}
const est = await nora.simulations.estimate({ /* config */ });

if (est.projectedUsd > 10) {
  throw new Error(`시뮬 예상 $${est.projectedUsd}, $10 상한 초과로 거절`);
}

const run = await nora.simulations.run("lin_1", {
  kind: "consistency",
  budgetUsd: Math.ceil(est.projectedUsd * 1.5),   // 여유 50%
});
```

### 진행 바로 폴링

```ts theme={null}
const run = await nora.simulations.run("lin_1", { kind: "consistency", budgetUsd: 5 });

for (;;) {
  const remaining = await nora.simulations.remaining(run.roundId);
  ui.progress({ done: total - remaining.count, total });
  if (remaining.count === 0) break;
  await sleep(5000);
}

const result = await nora.simulations.get(run.roundId);
if (result.delta > 0.10) {
  await nora.simulations.promote(run.roundId);  // → 개선 큐
}
```

### 시간 예산 + 확인

벽시계만 신경 쓰인다면, `budgetMinutes`와 함께 SDK가 `estimate` 대조로 확인할 비용 상한을 짝지으세요.

```ts theme={null}
await nora.simulations.run("lin_1", {
  kind: "consistency",
  budgetMinutes: 30,
  confirmUsdCeiling: 5,   // estimate > $5면 시작 거절
});
```

## 시뮬레이션이 루프에서 앉는 자리

```
실패 → 신호 → 군집 → [시뮬 = 근거] → 개선 → 승인 → 버전
                        ↑ SDK 노출         ↑ SDK 노출
```

SDK는 `simulations`(근거 생성기)와 `improvements`(결정 큐)를 노출합니다. 군집에서 초기 개선 후보를 만드는 것은 루프의 내부가 하는 일이지 SDK verb가 아닙니다. 후보가 생긴 뒤에는 여기서 다시 시뮬을 돌려 근거를 갱신하고 큐로 `promote`할 수 있습니다.
