# [16-2] mIRT 가상 코호트 시뮬레이터 기반 적응형 인지훈련 난이도 제어 엔진 — 설계 명세서

| 항목 | 내용 |
| --- | --- |
| 참조 하네스 | `cog16/t162.py` (표준 라이브러리 전용, Python 3.15.2에서 실행) |
| 고정 입력 | `cog16/fixtures/t162_cohort.json` (잠금 해시는 `cog16/_contract.py`의 `INPUT_LOCK_SHA256`) |
| 단위 시험 | `tests/test_cog16_t162.py` — 23건, `tests/test_cog16_audit.py` — 10건 |
| 실행 | `python3 -B -m cog16.orchestrate --output evidence/cog16-run.json` — 작업자 11개로 287–374초(다른 작업이 함께 도는 부하에서 3회 측정, CPU 합계 약 27–30분). 16-3 블록 포함 |
| 독립 감사 | `python3 -B -m cog16.audit --run evidence/cog16-run.json --output evidence/cog16-audit.json` — 약 1초. 풀이 모듈을 불러오지 않고 다시 계산한다(8.7절) |
| 자료 범위 | 합성 가상 코호트만 사용. ADNI·DementiaBank 원자료와 요약 메타데이터는 이 저장소에 없다 |

**이 문서의 수치가 뜻하는 것.** 9장의 수치는 fixture가 선언한 합성 가정 위에서 난이도 제어 정책이 수렴하는지를 오프라인으로 확인한 결과다. 가상 환자는 통계 분포에서 뽑은 확률적 응답 생성기이며 실제 환자의 발화나 인격을 모사하지 않는다. 치료 효능에 대한 주장은 없다. 정책의 내부 모형은 생성기와 같은 함수형을 쓰므로, 이 수치는 모형 구조가 맞는 경우의 결과다(11장). 코호트 모수는 ADNI·DementiaBank 요약 통계를 2.6절의 인터페이스로 반입하면 같은 하네스에서 다시 산출한다.

---

## 1. 범위와 안전 경계

1. **대상**: 과제 난이도 제어 정책의 수렴 안정성을 가상 코호트에서 검증하는 소프트웨어다. 임상 판단을 내리지 않는다.
2. **입력**: 영역별 인지 점수 분포의 요약 모수와 발화 지연시간 분포의 요약 모수만 받는다. 전사, 원음, 개별 대상 기록은 스키마에 없다. 하네스 출력의 모든 문자열은 코드 토큰이며 자유 문장을 내보내면 `free_text_paths` 검사가 실행을 거부한다.
3. **좌절 통제**: 연속 오답은 추상 정수(연속 오답 길이 $r$)로만 다룬다. 정책은 $r$에 따라 난이도를 낮추고, $r$이 상한에 닿으면 채점하지 않는 보조 시행을 끼워 넣는다(5장).
4. **실행 범위**: 응답 생성기, 상태 추정기, 제어 법칙, 판정기, 스트레스 시험은 모두 실행했다. 6.2절의 PyTorch 배치 인터페이스는 이 저장소에 torch가 없어 규격으로만 둔다.

---

## 2. 가상 코호트 상태 공간 모델

### 2.1 표기

| 기호 | 뜻 | 차원·값 |
| --- | --- | --- |
| $i, s, n$ | 환자, 세션, 세션 안 시행 순번 | $s \in \{0..11\}$, $n \in \{0..191\}$ |
| $k$ | 과제 유형 (`TK_MEM`, `TK_EXE`, `TK_VIS`, `TK_LAN`) | 6시행 블록으로 순환 |
| $\boldsymbol\theta_i$ | 잠재 인지 능력 (기억·집행·시공간·언어) | $\mathbb R^4$ |
| $\mathbf a_k$ | 과제 $k$의 영역 부하량 | $\mathbb R^4_{\ge 0}$ |
| $\mathbf u$ | 난이도 벡터 (`LOAD`, `PACE`, `INTERF`) | 격자 $\{0, \tfrac1{12}, .., 1\}^3$ |
| $\mathbf c_i$ | 환자별 노브 민감도 | $\mathbb R^3_{>0}$ |
| $r$ | 현재 연속 오답 길이 | 정수 |

### 2.2 환자 고정 모수 샘플링 규격

층 $g \in \{\text{MCI}, \text{EAD}\}$(경도인지장애, 초기 치매)마다 500명을 뽑는다. 아래 값은 fixture의 합성 가정이다.

| 모수 | 분포 | MCI | EAD |
| --- | --- | --- | --- |
| 능력 $\boldsymbol\theta_i$ | $\mathcal N(\boldsymbol\mu_g, D_g R D_g)$, $R$은 등상관 0.55 | $\boldsymbol\mu = (-1.0, -0.6, -0.4, -0.5)$, SD 0.70 | $(-2.0, -1.4, -1.1, -1.2)$, SD 0.75 |
| 노브 민감도 $c_{ij}$ | $\bar c_j \exp(\sigma_c z - \sigma_c^2/2)$, $\bar{\mathbf c} = (3.8, 2.9, 2.0)$ | $\sigma_c = 0.20$ | 0.20 |
| 변별 배율 $\alpha_i$ | $\exp(0.15 z)$ | 동일 | 동일 |
| 부주의율 $\lambda_i$ | 균등 | $[0.01, 0.05]$ | $[0.02, 0.08]$ |
| 학습 이득 $G_i$ | 로그정규(중앙값, $\sigma_{\log}$) | (0.35, 0.4) | (0.18, 0.4) |
| 피로 상한 $F_i$ | 로그정규 | (0.40, 0.35) | (0.70, 0.35) |
| 피로 시상수 $\tau_{F,i}$ | 로그정규 | (40시행, 0.3) | (40시행, 0.3) |
| 연속 오답 감점 $\psi_i$ | 균등 | $[0.05, 0.20]$ | $[0.08, 0.30]$ |
| 오후 저하 진폭 $A_i$ | 균등 | $[0, 0.3]$ | $[0.1, 0.6]$ |
| 속도 절편 $\tau_i$ | $m_g - 0.15\,\bar z_i + \sigma_\tau z$ ($\bar z_i$는 능력 표준점수 평균) | $(0, 0.25)$ | $(0.35, 0.30)$ |
| 세션 간 변동 SD $\sigma_{d}$ | 상수 | 0.08 | 0.12 |
| 피로 붕괴 위험 $h_0$ | 상수 | 0.0006 | 0.0012 |

능력 벡터는 $R$의 촐레스키 인자 $L$로 $\boldsymbol\theta_i = \boldsymbol\mu_g + \boldsymbol\delta + D_g L \mathbf z$로 만든다. $\boldsymbol\delta$는 분포 이동 시험이 넣는 평균 이동이며, 두꺼운 꼬리 시험에서는 $\mathbf z$에 $\sqrt{\nu/\chi^2_\nu}$를 곱한다.

### 2.3 상태 방정식

능력의 유효값은 고정 능력, 세션 간 변동, 학습 효과의 합이다.

$$\theta^{\text{eff}}_{i,d}(s,n) = \theta_{i,d} + \xi_{i,d,s} + G_i\left(1 - e^{-N_{i,d}/\tau_P}\right), \qquad \tau_P = 80$$

- **학습 효과**: $N_{i,d}$는 영역 $d$가 주 영역인 과제의 누적 채점 시행 수다. 세션이 바뀌면 $N_{i,d} \leftarrow 0.9\,N_{i,d}$로 일부를 잃는다.
- **세션 간 변동**: $\xi_{i,d,s} = 0.7\,\xi_{i,d,s-1} + \sigma_d\,\varepsilon$, $\varepsilon \sim \mathcal N(0,1)$.
- **세션 내 피로**: $f_{i}(n) = F_i\left(1 - e^{-n/\tau_{F,i}}\right)$.
- **일중 오프셋**: 세션 시작 시각 $h_s$(예정 시각에 $\pm 0.5$시간 흔들림)에서 $q_s = \operatorname{clip}\!\big((h_s - 12)/4, 0, 1\big)$, 감점 $A_i q_s$. $q_s$는 시계에서 나오는 값이므로 정책에도 문맥으로 준다.
- **피로 붕괴 레짐**: $Z_n \in \{0, 1\}$. $n \ge 20$에서 시행마다 확률 $h_0\,((n+1)/192)^2$로 $0 \to 1$이 되고 세션이 끝날 때까지 유지된다. 붕괴 시 능력 로짓 $-1.2$, 로그 지연시간 $+0.5$.
- **연속 오답 감점**: $\psi_i \min(r, 3)$.

감점 합은 $\pi_{i}(s,n) = f_i(n) + A_i q_s + \psi_i \min(r,3) + 1.2\,Z_n$ (급성 저하 시험에서는 여기에 상수를 더한다).

### 2.4 다차원 문항반응 방정식

보상형 다차원 로지스틱 모형에 추측 하한과 부주의 상한을 둔다.

$$\eta = \alpha_i\left(\mathbf a_k^\top \boldsymbol\theta^{\text{eff}}_i - \pi_i - b_k - \mathbf c_i^\top \mathbf u\right)$$

$$P_{\text{acc}} = g_k + (1 - g_k - \lambda_i)\,\sigma(\eta), \qquad \sigma(x) = \frac{1}{1 + e^{-x}}$$

$b_k$는 격자 원점의 기준 난이도, $g_k$는 과제별 추측 확률(0.02, 0.10, 0.25, 0.05)이다. 난이도 벡터는 $\mathbf c_i^\top \mathbf u$로만 들어가므로 세 노브가 한 척도 위에서 서로를 보상한다.

### 2.5 응답 지연시간 방정식과 결합 성공 확률

로그 지연시간은 로그정규 모형이다.

$$\log T = \beta_k + \tau_i + \boldsymbol\gamma^\top \mathbf u + 0.35\,f_i(n) + 0.5\,Z_n - 0.12\,\tanh(\eta/2) + 0.35\,\varepsilon$$

$\boldsymbol\gamma = (0.25, -0.20, 0.15)$이다. 속도 압박 노브 `PACE`는 응답을 빠르게 하지만 제한 시간도 줄인다. 제한 시간은 $\log T_{\max} = 2.708 - u_{\text{PACE}}$이고, 넘기면 오답으로 채점한다. 그래서 한 시행의 참 정반응 확률은 정확도와 시간 내 응답의 곱이다.

$$p^{\text{true}} = P_{\text{acc}} \cdot \Phi\!\left(\frac{\log T_{\max} - \mathbb E[\log T]}{0.35}\right)$$

하네스의 판정은 이 $p^{\text{true}}$를 쓴다. 시뮬레이터만 아는 값이므로 실배치용 판정은 7.4절에 따로 둔다.

### 2.6 fixture 스키마와 공개 자료 대응

| fixture 키 | 내용 | 반입할 요약 통계 |
| --- | --- | --- |
| `strata.<g>.abilityMean`, `abilitySd`, `design.abilityCorr` | 영역별 능력 평균·SD·상관 | ADNI 영역별 종단 신경심리 합성 점수의 층별 평균·공분산 (정상군 규준 대비 표준점수) |
| `strata.<g>.practiceGain`, `design.practiceTau`, `retention` | 학습 곡선 | ADNI 반복 검사에서의 재검 이득 요약 |
| `strata.<g>.driftSd`, `design.driftAr` | 방문 간 변동 | ADNI 종단 점수의 개인 내 잔차 분산 |
| `strata.<g>.speed`, `design.latSigma`, `latBase` | 응답 개시 지연 분포 | DementiaBank 그림 묘사 과제의 휴지 길이·발화 속도 요약 (층별 로그 평균·분산) |
| `strata.<g>.fatigueMax`, `fatigueTau`, `diurnal`, `crashHazard`, `runPenalty`, `lapse` | 상태 의존 모수 | 공개 요약 통계로 직접 식별되지 않는다. 문헌 범위를 사전 분포로 두고 8.4절의 분포 이동 시험으로 민감도를 본다 |

fixture는 `schemaVersion`, `seeds`, `cohort`, `design`, `strata`, `controller`, `judgement`, `sensitivity`, `shifts`, `faultInjection` 블록으로 이루어진다. JSON 파서는 중복 키와 비유한 수를 거부한다.

---

## 3. 상태 추정기

정책은 환자의 참 모수를 보지 못한다. 관측은 채점 결과 $y \in \{0,1\}$, 로그 지연시간, 시간 초과 여부, 그리고 문맥(과제 $k$, 시행 순번 $n$, 시계 문맥 $q_s$, 연속 오답 길이 $r$)이다.

### 3.1 확장 칼만 필터

상태는 11차원이다.

$$\mathbf s = \big[\underbrace{\theta_1..\theta_4}_{\text{능력}},\ \underbrace{c_1..c_3}_{\text{노브 민감도}},\ \phi,\ \omega,\ \psi,\ G\big]^\top$$

$\phi$는 피로 기울기, $\omega$는 오후 오프셋, $\psi$는 연속 오답 감점, $G$는 학습 이득이다. 회귀 벡터와 예측 로짓은

$$\mathbf z = \big[\mathbf a_k;\ -\mathbf u;\ -(1 - e^{-n/40});\ -q_s;\ -\min(r,3);\ \textstyle\sum_d a_{kd}(1 - e^{-\hat N_d/80})\big], \qquad m = \mathbf z^\top \hat{\mathbf s} - b_k$$

이고 $\hat N_d$는 정책이 스스로 세는 누적 시행 수다(세션 시작 때 0.9배). 관측 모형은 $h(m) = g_k + (1 - g_k - \lambda_0)\sigma(m)$, $\lambda_0 = 0.04$다.

시간 내 응답이 관측된 시행에서 한 번의 갱신은 다음과 같다.

$$h' = (1 - g_k - \lambda_0)\,\sigma(m)(1 - \sigma(m)), \quad v = \mathbf z^\top P \mathbf z, \quad S = h'^2 v + h(m)(1 - h(m))$$

$$\hat{\mathbf s} \leftarrow \hat{\mathbf s} + \frac{h'}{S} P\mathbf z\,\big(y - h(m)\big), \qquad P \leftarrow P - \frac{h'^2}{S}\,P\mathbf z\,(P\mathbf z)^\top, \qquad P \leftarrow P + Q$$

- 베르누이 분산 $h(1-h)$를 관측 잡음으로 쓰므로 정보 형식으로는 $P^{-1} \leftarrow P^{-1} + \frac{h'^2}{h(1-h)}\mathbf z \mathbf z^\top$, 즉 피셔 정보 가중 갱신이다.
- $Q$는 대각이다. 능력 $2\times10^{-5}$, 노브 $4\times10^{-6}\,\bar c_j^2$, 피로 $2\times10^{-5}$, 나머지 $10^{-5}$.
- 세션이 바뀌면 능력 대각에 $1.5\,\sigma_d^2$를 더해 세션 간 변동만큼 불확실성을 다시 연다.
- $\hat c_j \ge 0.25\,\bar c_j$로 사영해 난이도 단조성을 지킨다.
- 사전 분포는 층의 코호트 평균과 1.3배 넓힌 SD다. 능력 간 사전 상관은 0.55.
- 시간 초과 시행은 정확도에 대한 정보가 없으므로 이 필터를 갱신하지 않는다.

난이도 결정에는 플러그인 확률 $h(m)$을 쓴다. 불확실성 $v$는 비관적 하한(4.2절)에만 들어간다. 첫 구현은 예측 평균 근사 $\sigma(m/\sqrt{1 + \pi v/8})$로 결정했는데, 갱신의 혁신은 플러그인 $h(m)$ 기준이라 고정점이 어긋났다. 개발 시드에서 참 확률과 예측의 평균 차이는 0.018이었고, 결정과 갱신을 같은 양으로 맞춘 뒤 0.012, 학습 이득 상태 $G$를 넣은 뒤 0.006으로 줄었다.

### 3.2 지연시간 기준선 필터

스칼라 칼만 필터가 속도 절편 $\hat\tau$를 추적한다. 예측은 $\hat\mu_T = \beta_k + \hat\tau + \boldsymbol\gamma^\top\mathbf u + 0.2\,(1 - e^{-n/40})$, 관측 잡음 $\sigma_L = 0.37$, 과정 잡음 $5\times10^{-5}$다. 시간 초과는 중도절단 관측이므로 $\log T_{\max} + 0.5\sigma_L$을 4배 잡음으로 한 번 반영한다. 시간 내 응답 확률 예측은

$$\hat p_{\text{in}}(\mathbf u) = \Phi\!\left(\frac{\log T_{\max}(\mathbf u) - \hat\mu_T(\mathbf u)}{\sqrt{\sigma_L^2 + P_\tau}}\right)$$

### 3.3 BKT 형식 레짐 필터

몰입/피로 두 상태 은닉 마르코프 모형의 전방 재귀다. 베이지안 지식 추적과 같은 구조이고 상태의 뜻만 다르다. 피로 상태는 세션 안에서 흡수 상태다.

$$\pi^-_n = \pi_{n-1} + (1 - \pi_{n-1})\,a_n, \qquad a_n = 10^{-4} + 0.004\left(\tfrac{n+1}{192}\right)^2$$

$$\pi_n = \frac{\pi^-_n L_1}{\pi^-_n L_1 + (1 - \pi^-_n) L_0}$$

시간 내 응답이면 $L_0 = \varphi\!\big(\tfrac{e}{\sigma_L}\big)\,h(m)^y(1-h(m))^{1-y}$, $L_1 = \varphi\!\big(\tfrac{e - 0.5}{\sigma_L}\big)\,h(m - 1.2)^y(1 - h(m-1.2))^{1-y}$이고 $e = \log T - \hat\mu_T$다. 시간 초과면 두 상태의 초과 확률을 우도로 쓴다.

- $\pi_n \ge 0.2$이면 3.1·3.2절의 갱신을 멈춘다. 피로 구간의 응답이 능력과 속도 기준선으로 흡수되면 증거가 사라지기 때문이다.
- $\pi_n \ge 0.95$가 2시행 이어지면 세션을 정지한다(5장 `HALT_FATIGUE`).

### 3.4 급변 검출 변형 (`VAR_CHANGE_DETECT`, 1차 정책에서는 끔)

과정 잡음을 작게 둔 필터는 수준이 갑자기 바뀌면 느리게 따라간다. 변형 정책은 3.1절 갱신 때의 표준화 혁신 $\zeta_n = (y - h(m))/\sqrt{h(m)(1 - h(m))}$에 양측 누적합을 둔다.

$$S^+_n = \max(0,\ S^+_{n-1} + \zeta_n - k), \qquad S^-_n = \max(0,\ S^-_{n-1} - \zeta_n - k)$$

$\max(S^+_n, S^-_n) > h$이면 능력 블록에 공통 방향 분산을 더하고 두 합을 0으로 되돌린다.

$$P_{\theta\theta} \leftarrow P_{\theta\theta} + q_c\,\mathbf 1\mathbf 1^\top$$

- 설정은 $k = 0.10$, $h = 22$, $q_c = 0.16$이다. 개발 시드에서 급락 직후의 $\zeta$ 평균이 약 $-0.23$이어서 기준값 $k$를 그 절반 근처에 두었다.
- 선택 규칙은 개발 시드에서 미리 정했다. 기본 코호트 수렴률 손실이 0.5%p 이내인 설정 가운데 급성 저하 시나리오 수렴률이 가장 높은 것을 고른다. 개발 시드 400명에서 기본 97.0%(검출 없음 97.5%), 급성 저하 55.0%(검출 없음 32.5%)였다.
- 피로 정지로 끝난 세션 뒤에는 두 합을 0으로 되돌린다. 레짐 필터가 피로로 본 시행($\pi_n \ge 0.2$)은 누적합에 넣지 않는다.
- 재개방은 다음 시행부터 예측 분산 $v$와 비관적 하한에 들어가 후보 선택을 바꾼다. 1차 정책에서는 검출기가 꺼져 있어 이 경로가 없다. 감사기는 1차 실행의 재개방 횟수가 0인지 확인하고, 1차·반복·기준 정책·분포 이동·결함 주입 실행의 수치는 검출기를 추가하기 전 증거 문서와 같았다.
- 평가 시드를 이미 본 뒤에 추가한 장치이므로 1차 정책에는 넣지 않고 변형으로만 측정했다(9.8절).

---

## 4. 안전 제약형 컨텍스추얼 밴딧 제어 법칙

### 4.1 행동 집합과 슬루 제한

과제마다 마지막으로 제시한 격자점 $\mathbf u^{(k)}$를 기억한다. 한 시행의 후보는 그 점에서의 제한된 이동이다.

| 조건 | 허용 이동 |
| --- | --- |
| $r = 0$이고 $\pi^- < 0.2$ | 유지, 한 노브 $\pm 1$ 또는 $\pm 2$ 수준, 전 노브 $\pm 1$ 수준 (15개) |
| $r \ge 1$ 또는 $\pi^- \ge 0.2$ | 유지, 한 노브 $-1$ 또는 $-2$, 전 노브 $-1$ 또는 $-2$ (9개). 어떤 노브도 올리지 않는다 |
| $r = 0$이고 직전 오답 구간이 정답으로 끝남 | 위에 더해, 그 구간이 시작된 격자점으로의 복귀 1개 |

상향은 한 시행에 한 노브 2수준 또는 전 노브 1수준이 상한이다. 하향은 더 크게 허용한다.

### 4.2 안전 집합

후보 $\mathbf u$의 예측과 비관적 하한은

$$\hat p(\mathbf u) = \big[(1 - \pi^-)\,h(m(\mathbf u)) + \pi^-\,h(m(\mathbf u) - 1.2)\big]\,\hat p_{\text{in}}(\mathbf u)$$

$$\underline p(\mathbf u) = \big[(1 - \pi^-)\,h(m - \beta\sqrt v) + \pi^-\,h(m - \beta\sqrt v - 1.2)\big]\,\hat p_{\text{in}}(\mathbf u), \qquad \beta = 1$$

이다. 레짐 혼합 항은 $\pi^- > 0.02$일 때만 계산한다. 안전 집합은 연속 오답 길이에 따라 바닥이 올라간다.

$$\mathcal S_n = \{\mathbf u \in \mathcal C_n : \underline p(\mathbf u) \ge \rho(r)\}, \qquad \rho(0) = 0.55,\ \rho(1) = 0.66,\ \rho(r \ge 2) = 0.82$$

$\mathcal S_n$이 비면 후보 중 $\hat p$가 가장 큰 점을 고른다(`EASE_FORCED`).

### 4.3 목적 함수: 추종 손실과 쌍대 가격

$$\mathbf u_n = \arg\min_{\mathbf u \in \mathcal S_n}\ \left(\frac{\hat p(\mathbf u) - p^\star_n}{0.05}\right)^2 + \lambda_n\,w(r)\,\big(1 - \hat p(\mathbf u)\big) - \kappa\sqrt{v(\mathbf u)} + \mu\,\lVert \Delta \text{수준} \rVert_1$$

- **쌍대 변수**: 좌절 사건 $E_n = \mathbb 1[r_{n+1} \ge 3]$의 장기 빈도 제약 $\mathbb E[E] \le \rho_{\max} = 0.03$을 사영 부분경사로 가격에 넣는다. $\lambda_{n+1} = \operatorname{clip}\big(\lambda_n + 0.5\,(E_n - \rho_{\max}),\ 0,\ 4\big)$, $w = (0, 0.25, 1)$.
- **탐색 항**: $\kappa = 0.05$. 예측 분산이 큰 격자점에 작은 가산점을 준다.
- **이동 비용**: $\mu = 0.02$ (수준당).
- **경험 성공률 중심화**: 안전 시행(`GUARD`, `EASE`)은 일부러 쉽게 내므로 환자가 겪는 평균 성공률이 목표보다 올라간다. 적분기 $\iota_{n+1} = \operatorname{clip}\big(\iota_n + 0.01\,(\hat p_n - 0.75),\ \pm 0.04\big)$로 일반 시행의 목표를 $p^\star_n = \operatorname{clip}(0.75 - \iota_n,\ 0.71,\ 0.79)$로 옮긴다. $r \ge 2$에서는 $p^\star = 0.75$로 두고 바닥 제약이 결정한다.

### 4.4 시작 난이도

과제마다 세 노브가 같은 수준인 격자점 가운데 사전 분포 아래 $\underline p \ge 0.80$을 만족하는 가장 어려운 점에서 시작한다.

---

## 5. 실패 안전 상태 기계

소프트웨어 안전 등급은 위해 분석에 따라 정하되, 이 엔진은 난이도만 바꾸고 진단·투약 판단을 내리지 않으며 아래 인터록이 과도한 난이도를 구조적으로 막는다. 설계는 IEC 62304의 위험 통제 조치를 소프트웨어 항목으로 분리하는 방식에 맞춘다. 제어 법칙(4장)과 독립 감시기(5.2절)를 서로 다른 항목으로 두고, 감시기는 제어기 내부 상태를 읽지 않는다.

### 5.1 상태와 전이

| 상태 | 진입 조건 | 동작 | 이탈 |
| --- | --- | --- | --- |
| `ADAPT` | $r = 0$ | 4.1–4.3절의 일반 결정 | 오답 → `GUARD` |
| `GUARD` | $r = 1$ | 하향 이동만, 바닥 0.66 | 정답 → `ADAPT`/`RESTORE`, 오답 → `EASE` |
| `EASE` | $r \ge 2$ | 하향 이동만, 바닥 0.82 | 정답 → `ADAPT`/`RESTORE` |
| `EASE_FORCED` | 안전 집합이 빔 | 후보 중 가장 쉬운 점 | 다음 시행에서 재평가 |
| `RESTORE` | 오답 구간이 정답으로 끝난 직후 | 구간 시작 격자점으로 복귀(안전 집합 안일 때만) | `ADAPT` |
| `SUPPORT` | $r = 4$ | 채점하지 않는 보조 시행. 해당 과제 기준 수준을 전 노브 2수준 내림. $r \leftarrow 0$ | `ADAPT` |
| `HALT_FATIGUE` | $\pi \ge 0.95$가 2시행 연속 | 세션 종료 | 다음 세션 |
| `HALT_RANGE_FLOOR` | 격자 원점에서 $\hat p < 0.65$가 누적 12회 | 세션 종료, 환자에 범위 하한 포화 표지 | 임상의 검토 |
| (범위 상한 표지) | 격자 최댓점에서 $\hat p > 0.85$가 12회 이상 | 계속 진행, 범위 상한 포화 표지 | 임상의 검토 |
| `FALLBACK` | 필터 상태가 비유한이거나 분산이 0 이하 | 3:1 가중 계단법으로 전환. 오답 직후 상향 금지와 `SUPPORT`는 유지 | 다음 세션에서 사전 분포로 필터 재구성, 마지막 제시 수준에서 재개 |

범위 포화 표지가 선 환자는 수렴 판정에서 제외하지 않는다. 미수렴으로 센다.

### 5.2 독립 감시기 불변식

`run_patient` 안의 감시기는 제시된 격자점과 채점 결과만 보고 다음을 매 시행 검사한다. 위반 수는 증거 문서의 `monitor.violations`에 남고 0이어야 한다.

1. 모든 수준이 격자 $[0, 12]$ 안이다.
2. 과제의 직전 제시 수준 대비 상향은 한 노브 2수준 이하이거나 전 노브 1수준 이하다. 예외는 `RESTORE`이고 그 목표는 감시기가 따로 기록한 오답 구간 시작 수준과 같아야 한다.
3. 직전 시행이 오답이면 어떤 노브도 올라가지 않는다.
4. 보조 시행 없이 채점된 연속 오답이 4를 넘지 않는다.

### 5.3 모형이 틀렸을 때의 동작

- 능력이 격자 범위 밖이면 수렴을 지어내지 않는다. `CASE_FLOOR_UNREACHABLE`과 `CASE_CEILING_UNREACHABLE`에서 오라클 판정과 실배치용 판정이 모두 미수렴으로 나와야 한다.
- 필터 결함은 주입 시험(8.5절)으로 확인한다. 결함 뒤에도 감시기 위반은 0이어야 한다.

---

## 6. 모듈 인터페이스

### 6.1 참조 구현 (실행됨)

```python
class Design:                      # 과제 배터리와 노브 격자 (불변)
    def task_of(self, n: int) -> int: ...

def sample_patient(rng: Rng, stratum: str, design: Design, sc: dict,
                   shift: dict | None = None) -> dict: ...

class Env:                         # 가상 환자 응답 생성기
    def start_session(self, s: int) -> float: ...              # 시계 문맥 q_s 반환
    def step(self, k: int, lev: Sequence[int], n: int
             ) -> tuple[int, float, bool, float]: ...          # (y, log T, timeout, p_true)
    def support(self) -> None: ...                             # 채점하지 않는 보조 시행

class Scheduler:                   # 추정기 + 제어 법칙 + 상태 기계
    def start_session(self, s: int, pm: float) -> None: ...
    def act(self, k: int, n: int) -> tuple[int, tuple[int, int, int] | None]: ...
    def observe(self, y: int, log_t: float, timeout: bool) -> None: ...
    def predicted(self) -> float: ...
    halted: bool; halt_code: str

class Staircase: ...               # 기준 정책이자 FALLBACK
def judge(p_true, y, planned, jd, breaks=()) -> dict: ...      # 7장의 판정
def run_patient(design, cfg, pat, policy, seed, inject=None) -> dict: ...
def run_cohort(cfg, seed, per_stratum, policy, shift=None, inject=None) -> dict: ...
def protocol_cases(cfg) -> dict: ...
def run_block(cfg, workers=None, per_stratum=None) -> dict: ...
```

`Scheduler`는 `Env`의 내부를 읽지 않는다. 주고받는 것은 `act`의 격자점과 `observe`의 세 관측뿐이다.

### 6.2 PyTorch 배치 인터페이스 (규격, 미실행)

코호트를 한 번에 돌리는 벡터화 구현의 계약이다. 수식은 3–4장과 같고 텐서의 첫 축이 환자다.

```python
class CohortParams(NamedTuple):
    theta: Tensor      # [B, 4]
    knob: Tensor       # [B, 3]
    slope: Tensor      # [B]
    lapse: Tensor      # [B]
    ...                # 2.2절의 나머지 모수

class MirtCohortEnv(torch.nn.Module):
    def __init__(self, design: DesignTensors, params: CohortParams, generator: torch.Generator): ...
    def start_session(self, s: int) -> Tensor: ...             # q_s [B]
    def step(self, task: Tensor, level: Tensor, n: int
             ) -> tuple[Tensor, Tensor, Tensor, Tensor]: ...   # y [B], log_t [B], timeout [B], p_true [B]

class EkfState(NamedTuple):
    mean: Tensor       # [B, 11]
    cov: Tensor        # [B, 11, 11]
    tau: Tensor        # [B] 지연시간 절편
    tau_var: Tensor    # [B]
    regime: Tensor     # [B] 피로 사후 확률

class SafeBanditScheduler(torch.nn.Module):
    def act(self, state: EkfState, task: Tensor, n: int, run: Tensor, clock: Tensor
            ) -> tuple[Tensor, Tensor]: ...                    # level [B, 3], machine_state [B]
    def observe(self, state: EkfState, y: Tensor, log_t: Tensor, timeout: Tensor) -> EkfState: ...
```

- 후보 평가는 `[B, 16, 3]` 격자 이동 텐서에 대한 마스크 argmin이다. 격자 밖, 슬루 위반, $\underline p < \rho(r)$는 `+inf`로 가린다.
- 공분산 갱신은 계수 1 다운데이트이므로 `torch.baddbmm` 한 번이다.
- 합격 기준은 참조 구현과의 동치다. 같은 fixture와 같은 난수열에서 환자별 격자점 수열이 일치해야 하고, 부동소수 차이로 argmin 동률이 갈리는 시행은 목록으로 보고한다.

---

## 7. 수렴 판정의 수학적 정의

### 7.1 정의

환자 $i$에게 제시되어 채점된 시행을 순서대로 $t = 1..T_i$라 하고, 창 길이 $W = 192$(한 세션)의 이동 평균을 둔다.

$$\bar p_t = \frac{1}{W}\sum_{j = t - W + 1}^{t} p^{\text{true}}_j, \qquad t \ge W$$

목표 구간 $\mathcal B = [0.70, 0.80]$은 $p^\star = 0.75$의 $\epsilon = 0.05$ 밴드다. 보호 구간은 $\mathcal G = [0.65, 0.85]$.

- **진입점**: $t$가 진입점 ⟺ $\bar p_j \in \mathcal B$ for all $j \in [t, t + H - 1]$, $H = 192$.
- **정착 시간**: $\tau_i = \min\{t : t\text{는 진입점},\ \tfrac{1}{T_i - t + 1}\sum_{j \ge t}\mathbb 1[\bar p_j \in \mathcal B] \ge 0.90,\ \bar p_j \in \mathcal G\ \forall j \ge t\}$.
- **정밀도**: $\text{RMS}_i = \sqrt{\tfrac{1}{T_i - \tau_i + W}\sum_{j > \tau_i - W}(p^{\text{true}}_j - 0.75)^2} \le 0.08$. 창 평균만 구간 안이고 시행별 확률은 크게 흔들리는 경우를 걸러낸다.
- **노출**: $T_i \ge 0.6 \times 2304$.
- **수렴**: $C_i = \mathbb 1[\tau_i \le T_{\text{dead}}] \cdot \mathbb 1[\text{RMS}_i \le 0.08] \cdot \mathbb 1[\text{노출}]$, $T_{\text{dead}} = 768$(4세션).

정착 시간은 제어 이론의 정의(그 뒤로 밴드를 벗어나지 않는 가장 이른 시각)에 확률계용 허용 비율 10%를 둔 것이다. 처음 통과한 진입점을 $\tau_i$로 고정하는 더 엄격한 읽기도 민감도 항목(`SENS_FIRST_PASSAGE`)으로 함께 보고한다.

### 7.2 좌절 제약과 결합 성공

채점된 시행 수열에서 길이 3 이상인 연속 오답 구간의 셋째 이후 시행을 좌절 사건으로 센다. 세션이 바뀌면 구간을 끊는다. 보조 시행은 구간을 끊지 않는 것으로 센다(보수적).

$$\text{FR}_i = \frac{1}{T_i}\sum_t \mathbb 1[\text{시행 } t \text{가 연속 오답의 셋째 이후}] \le 0.03$$

**결합 성공** $J_i = C_i \cdot \mathbb 1[\text{FR}_i \le 0.03]$, **난이도 수렴률** $\hat R = \tfrac{1}{N}\sum_i J_i$.

### 7.3 게이트

- 점추정: $\hat R \ge 0.95$.
- 하한: 단측 95% Clopper–Pearson 하한 $R_L \ge 0.95$. $N = 1000$에서는 962명 이상이 필요하다($k = 962$일 때 $R_L = 0.9505$, $k = 961$일 때 $0.9494$).
- 층별 점추정: MCI, EAD 각각 $\ge 0.95$.
- 감시기 위반 0.

### 7.4 실배치용 판정

참 확률은 실배치에서 볼 수 없다. 같은 규칙을 정책의 예측 확률 $\hat p_t$에 적용하고, 정착 뒤 $\lvert \overline{y} - \overline{\hat p} \rvert \le 0.05$(예측 보정)와 범위 포화 표지 없음을 추가로 요구한다. 하네스는 이 판정과 오라클 판정의 일치를 `observable` 블록으로 보고한다.

### 7.5 세션 설계의 근거: 이진 응답의 정보 하한

이진 응답만으로 성공 확률 수준을 추정할 때 $n$시행의 표준오차는 $\sqrt{p(1-p)/n}$이다. $p = 0.75$, $\epsilon = 0.05$에서 수준 오차를 95% 신뢰로 밴드 안에 두려면

$$n \ge p(1-p)\left(\frac{1.96}{\epsilon}\right)^2 \approx 288 \text{ 시행}$$

이 필요하다. 어떤 추정기도 이보다 적은 정보로는 밴드 유지를 보장하지 못한다. 설계는 이 하한에서 나왔다.

- 창과 유지 길이를 48시행으로 두면 창 안의 과제 구성 불균형과 추정 잡음이 밴드 폭과 같은 크기가 된다. 개발 시드에서 세션 144시행·창 48로 69%, 창 144로 90–93%였다.
- 세션을 192시행(4과제 × 6시행 블록 × 8순환)으로 두고 창을 한 세션으로 잡으면 개발 시드 400명에서 97.5%가 나왔다.
- 진입 기한 4세션(768시행)은 하한의 약 2.7배다.

개발 시드(162011)에서만 설계와 제어기 설정을 정했고, 평가 시드(162023, 162029, 162031)는 설정을 고정한 뒤에 돌렸다.

---

## 8. 검증 프로토콜

### 8.1 몬테카를로 구성

- 층화 코호트 1,000명(MCI 500, EAD 500), 환자당 12세션 × 192시행 = 2,304시행.
- 환자 $i$의 모수 시드와 응답 잡음 시드는 `(seed, 층, 순번)`에서 결정적으로 만든다. 응답 난수는 세션 시작 때 미리 뽑아 두므로 정책이 달라도 같은 환자는 같은 난수열을 받는다.
- 1차 실행 `PRIMARY`(시드 162023), 반복 `REPLICATE_1`, `REPLICATE_2`. 세 실행을 합친 3,000명의 수렴률과 하한도 보고한다.

### 8.2 기준 정책과 절제

| 정책 | 내용 |
| --- | --- |
| `SAFE_BANDIT` | 3–5장 전체 |
| `ABL_NO_SAFETY` | 비관적 하한 바닥, 쌍대 가격, 보조 시행, 피로 정지를 끔 |
| `BASE_STAIRCASE` | 모형 없는 3:1 가중 계단법 |
| `BASE_FIXED` | 층 평균에서 0.75가 되는 고정 난이도 |
| `VAR_CHANGE_DETECT` | `SAFE_BANDIT`에 3.4절의 급변 검출을 켠 변형. 기본 코호트와 급성 저하 시나리오에서 측정 |

### 8.3 판정 정의 민감도

같은 궤적에 다른 정의를 적용한 수렴률을 `sensitivity` 블록에 남긴다. 창 48·384, 기한 576·960, 유지 비율 0.95·1.00, RMS 0.07, 최초 통과 고정.

### 8.4 분포 이동 스트레스 시험

정책의 사전 분포와 설정은 그대로 두고 생성 분포만 옮긴다. 각 1,000명.

| ID | 이동 |
| --- | --- |
| `SH_SEVERITY_M05`, `SH_SEVERITY_M10`, `SH_MILD_P10` | 능력 평균 $-0.5$, $-1.0$, $+1.0$ |
| `SH_FATIGUE_X2` | 피로 상한과 붕괴 위험 2배 |
| `SH_PRACTICE_X0`, `SH_PRACTICE_X3` | 학습 이득 0배, 3배 |
| `SH_LAPSE_P06`, `SH_GUESS_P10` | 부주의율 $+0.06$, 추측 확률 $+0.10$ |
| `SH_SLOPE_X06`, `SH_SLOPE_X15` | 변별 배율 0.6배, 1.5배 |
| `SH_KNOB_HETERO` | 노브 민감도 이질성 2.5배 |
| `SH_LATENCY_SLOW` | 로그 지연시간 $+0.4$ |
| `SH_HEAVY_TAIL` | 능력 분포를 자유도 4의 $t$ 분포로 |
| `SH_ACUTE_DROP` | 5번째 세션부터 능력 로짓 $-0.8$ |

게이트를 넘지 못한 시나리오는 `shiftGateFailed`에 그대로 남긴다.

### 8.5 결함 주입과 프로토콜 사례

- **결함 주입**: 40명에게 3번째 세션의 31번째 시행에서 필터 상태를 비유한으로 바꾼다. `FALLBACK` 전환, 감시기 위반 0, 다음 세션 재개를 확인한다.
- **프로토콜 사례**: 공통 감사 프로토콜의 16-2 행(상향·하향 수렴, 피로 시 정지, 목표 구간 미수렴)에 대응한다.

| 사례 | 구성 | 합격 조건 |
| --- | --- | --- |
| `CASE_UPWARD` | 능력이 사전 평균보다 1.4 높음 | 결합 성공, 감시기 위반 0 |
| `CASE_DOWNWARD` | 능력이 사전 평균보다 1.6 낮음 | 결합 성공, 감시기 위반 0 |
| `CASE_FATIGUE_STOP` | 2번째 세션 41번째 시행에 붕괴 강제 | 그 세션에서 `HALT_FATIGUE`, 지연 15시행 이하 |
| `CASE_FLOOR_UNREACHABLE` | 능력이 4.5 낮음 | 오라클·실배치 판정 모두 미수렴, 범위 하한 표지 |
| `CASE_CEILING_UNREACHABLE` | 능력이 5.5 높음 | 오라클·실배치 판정 모두 미수렴, 범위 상한 표지 |

### 8.6 재현성

증거 문서는 fixture 잠금 해시, 실행 결과, 문서 해시를 담는다. `python3 -B -m cog16.orchestrate --check evidence/cog16-run.json`은 다시 실행해 바이트 단위로 비교한다. 작업자 프로세스 수는 결과에 영향을 주지 않는다.

### 8.7 독립 감사

`cog16/audit.py`는 `t162`·`t163`을 불러오지 않는다. 함께 쓰는 것은 `_contract.py`의 직렬화·해시 도우미와 고정 fixture뿐이다. 증거 문서에는 감사가 다시 계산할 재료를 함께 싣는다. 1차 실행의 환자별 정수 행 1,000개, 프로토콜 사례 5건의 시행별 참 확률(백만분율 정수)과 채점 결과, 세션 경계다.

| 대상 | 실행기 | 감사기 |
| --- | --- | --- |
| 1차 실행의 성공 수, 층별 수, 조건별 수, 정착 시간 분위수 | 환자별 판정에서 집계 | 증거 문서의 환자별 행에서 다시 집계하고 행 안의 논리(수렴 = 정착·정밀·노출)도 확인 |
| Clopper–Pearson 하한·상한 254개 | 로그 감마 부동소수 합과 이분법 | 보고된 한계의 $\pm10^{-6}$을 정수 산술 이항 꼬리 방정식에 대입 |
| 수렴 판정(진입점, 정착 시간, 밴드 내 비율, RMS, 좌절 사건) | 부동소수 이동 합 | 궤적에서 정수 누적합으로 다시 유도. 반올림 여유 안의 창은 양쪽으로 계산해 범위를 확인 |
| 게이트 표지, 합산, 분포 이동 통과 목록 | 실행 중 계산 | 보고된 수에서 다시 계산 |

관문은 넷이다. G1 동결 입력과 제출 구조, G2 판정 정의·통제 완전성과 구조 규칙, G3 독립 재계산, G4 가상 지표 판정. 두 프로그램은 같은 파일 권한으로 돌며 정답을 숨긴 블라인드 환경은 아니다. 감사 문서의 `humanAuditorSignature`는 비어 있다.

---

## 9. 하네스 실측 결과 (합성 가상 코호트)

증거 문서 `evidence/cog16-run.json`. fixture 잠금 `7d2b1a89fbdce835…`, 문서 해시 `7a8639328bb25ec9…`. 아래 수치는 모두 그 문서에서 옮겼다. 독립 감사 문서 `evidence/cog16-audit.json`은 이 문서에 대해 관문 4개를 모두 통과했다.

**요약.** 1차 실행은 962/1000(96.2%, 하한 0.9505)로 두 게이트를 넘었다. 다만 (1) 반복 실행 하나는 하한과 층별 게이트를 넘지 못했고, (2) 같은 궤적에 판정 정의만 바꾸면 수렴률이 81.1%에서 97.2%까지 움직인다. 95% 이상이라는 결론은 7.1절의 정의와 7.5절의 세션 설계 위에서만 성립하며 여유가 크지 않다.

### 9.1 난이도 수렴률

| 실행 (시드) | 결합 성공 | 수렴률 | 단측 95% 하한 | MCI | EAD | 점추정 게이트 | 하한 게이트 | 층별 게이트 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| `PRIMARY` (162023) | 962/1000 | 96.2% | 0.9505 | 484/500 (96.8%) | 478/500 (95.6%) | 통과 | 통과 | 통과 |
| `REPLICATE_1` (162029) | 973/1000 | 97.3% | 0.9630 | 487/500 (97.4%) | 486/500 (97.2%) | 통과 | 통과 | 통과 |
| `REPLICATE_2` (162031) | 955/1000 | 95.5% | 0.9427 | 482/500 (96.4%) | 473/500 (94.6%) | 통과 | 미달 | 미달 |
| 세 실행 합산 | 2890/3000 | 96.3% | 0.9572 | | | | | |

- 1차 실행은 점추정과 하한 게이트를 모두 넘었다. 하한 0.9505는 기준 0.95와 0.0005 차이로, 한 명이 더 실패했다면 넘지 못했다.
- `REPLICATE_2`는 점추정(95.5%)은 넘었지만 하한(0.9427)과 층별 게이트(EAD 94.6%)는 넘지 못했다. 세 실행을 합치면 96.3%(하한 0.9572)다. 1,000명 한 번의 실행이 하한 게이트를 넘는다고 보장할 만큼의 여유는 없다.
- 1차 실행의 조건별 충족 수(1000명 중): 기한 내 최초 진입 995, 기한 내 정착 965, 정밀도 994, 노출 1000, 수렴 963, 좌절 제약 998.
- 정착 시간: 중앙값 192번째 시행(첫 창), 90백분위 394, 99백분위 1737. 정착 뒤 창이 밴드 안에 있는 비율은 환자 평균 98.9%, 시행별 RMS 중앙값은 0.055이다.
- 범위 포화: 하한 1명, 상한 1명. 감시기 위반 0건, 필터 결함 0건.

### 9.2 좌절 제약과 안전 상태

- 좌절 사건률: 환자 평균 0.0085, 최댓값 0.0368. 상한 0.03을 넘은 환자는 2명이다.
- 최장 연속 오답(보조 시행을 구간 끊김으로 세지 않는 보수적 집계): 9. 보조 시행 없이 이어진 채점 오답은 감시기 불변식에 따라 4를 넘지 않았다.
- 상태 점유(전체 2,275,360 시행 슬롯): `ADAPT` 73.7%, `GUARD` 19.0%, `EASE` 3.0%, `EASE_FORCED` 2.6%, `RESTORE` 1.6%, `SUPPORT` 2,565회(환자당 2.6회).
- 피로 정지: 붕괴가 일어난 658세션 중 585세션을 정지했다(88.9%). 붕괴에서 정지까지 중앙값 9시행, 90백분위 14시행. 붕괴 없는 세션의 오정지는 25건으로 전체 12,000세션의 0.2%다. 정지하지 못한 73세션의 원인은 이 실행에서 집계하지 않았다.

### 9.3 기준 정책과 절제 (시드 162023, 같은 환자·같은 난수열)

| 정책 | 결합 성공 | 수렴 | 좌절 제약 충족 | 좌절 사건률 평균 | 최댓값 | 최장 연속 오답 | RMS 중앙값 |
| --- | --- | --- | --- | --- | --- | --- | --- |
| `SAFE_BANDIT` | 962/1000 (96.2%) | 963 | 998 | 0.0085 | 0.0368 | 9 | 0.055 |
| `ABL_NO_SAFETY` | 936/1000 (93.6%) | 937 | 997 | 0.0154 | 0.0387 | 11 | 0.045 |
| `BASE_STAIRCASE` | 1/1000 (0.1%) | 1 | 997 | 0.0130 | 0.0586 | 9 | 0.118 |
| `BASE_FIXED` | 92/1000 (9.2%) | 108 | 406 | 0.0904 | 0.6788 | 88 | 1.000 |

- 안전 계층을 끄면 좌절 사건률 평균이 0.0085에서 0.0154로 1.8배가 되고 결합 성공은 936명으로 줄었다. 절제 정책에는 피로 정지가 없어 붕괴 뒤에도 세션이 이어진다. 결합 성공이 줄어든 원인을 항목별로 나누지는 않았다.
- 계단법은 창 평균은 목표 근처에 두지만 시행별 확률이 크게 흔들려(RMS 중앙값 0.118) 정밀도 조건에서 탈락한다. 고정 난이도는 92명만 성공했다.

### 9.4 판정 정의 민감도 (1차 실행의 같은 궤적)

| 정의 변경 | 결합 성공 | 수렴률 | 하한 |
| --- | --- | --- | --- |
| (기준 정의) | 962/1000 | 96.2% | 0.9505 |
| 진입 기한 576(3세션) `SENS_DEADLINE_576` | 952/1000 | 95.2% | 0.9393 |
| 진입 기한 960(5세션) `SENS_DEADLINE_960` | 972/1000 | 97.2% | 0.9618 |
| 정착 시간을 최초 진입점으로 고정 `SENS_FIRST_PASSAGE` | 957/1000 | 95.7% | 0.9449 |
| 유지 비율 0.95 `SENS_MAINTAIN_095` | 897/1000 | 89.7% | 0.8798 |
| 유지 비율 1.00(이탈 불허) `SENS_MAINTAIN_100` | 811/1000 | 81.1% | 0.7895 |
| RMS 상한 0.07 `SENS_RMS_007` | 934/1000 | 93.4% | 0.9196 |
| 창·유지 48시행 `SENS_WINDOW_048` | 913/1000 | 91.3% | 0.8969 |
| 창 384시행(2세션) `SENS_WINDOW_384` | 970/1000 | 97.0% | 0.9595 |

수렴률은 판정 정의에 민감하다. 창을 48시행으로 줄이면 91.3%, 정착 뒤 이탈을 전혀 허용하지 않으면 81.1%로 내려간다. 95% 이상이라는 결론은 7.1절의 정의(한 세션 창, 이탈 허용 10%, 기한 4세션)에 한정된다.

### 9.5 실배치용 판정과 오라클 판정의 일치

- 실배치용 판정이 수렴이라고 한 997명 중 오라클도 성공인 환자는 961명이다(양성 예측도 96.4%).
- 오라클이 실패로 본 38명 중 실배치용 판정이 걸러낸 환자는 2명뿐이다. 수준 추정 오차로 인한 미수렴은 예측 확률 자체가 밴드 안에 있어서 예측 기반 판정으로는 드러나지 않는다. 범위 포화처럼 정책이 스스로 아는 실패만 잡힌다.
- 정착 뒤 예측 보정 차이 $\lvert\overline y - \overline{\hat p}\rvert$의 90백분위는 0.0106다.

### 9.6 분포 이동 스트레스 시험 (각 1,000명, 시드 162023)

| 시나리오 | 결합 성공 | 수렴률 | 하한 | MCI | EAD | 하한 포화 | 상한 포화 | 오정지 | 점추정 | 하한 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| `SH_SEVERITY_M05` | 959/1000 | 95.9% | 0.9471 | 482 | 477 | 4 | 0 | 19 | 통과 | 미달 |
| `SH_SEVERITY_M10` | 950/1000 | 95.0% | 0.9371 | 486 | 464 | 20 | 0 | 17 | 통과 | 미달 |
| `SH_MILD_P10` | 937/1000 | 93.7% | 0.9229 | 472 | 465 | 0 | 25 | 52 | 미달 | 미달 |
| `SH_FATIGUE_X2` | 902/1000 | 90.2% | 0.8851 | 479 | 423 | 7 | 0 | 288 | 미달 | 미달 |
| `SH_PRACTICE_X0` | 946/1000 | 94.6% | 0.9327 | 478 | 468 | 1 | 0 | 25 | 미달 | 미달 |
| `SH_PRACTICE_X3` | 898/1000 | 89.8% | 0.8809 | 436 | 462 | 0 | 12 | 22 | 미달 | 미달 |
| `SH_LAPSE_P06` | 978/1000 | 97.8% | 0.9687 | 490 | 488 | 2 | 0 | 17 | 통과 | 통과 |
| `SH_GUESS_P10` | 962/1000 | 96.2% | 0.9505 | 483 | 479 | 0 | 2 | 23 | 통과 | 통과 |
| `SH_SLOPE_X06` | 985/1000 | 98.5% | 0.9770 | 495 | 490 | 6 | 0 | 23 | 통과 | 통과 |
| `SH_SLOPE_X15` | 868/1000 | 86.8% | 0.8491 | 439 | 429 | 0 | 2 | 24 | 미달 | 미달 |
| `SH_KNOB_HETERO` | 882/1000 | 88.2% | 0.8639 | 426 | 456 | 1 | 34 | 27 | 미달 | 미달 |
| `SH_LATENCY_SLOW` | 924/1000 | 92.4% | 0.9088 | 478 | 446 | 2 | 0 | 129 | 미달 | 미달 |
| `SH_HEAVY_TAIL` | 924/1000 | 92.4% | 0.9088 | 468 | 456 | 9 | 10 | 30 | 미달 | 미달 |
| `SH_ACUTE_DROP` | 360/1000 | 36.0% | 0.3349 | 199 | 161 | 5 | 0 | 22 | 미달 | 미달 |

- 14개 시나리오 중 점추정 95%를 넘은 것은 5개, 하한 게이트까지 넘은 것은 3개다. 감시기 위반은 14개 모두 합쳐 0건이다.
- `SH_ACUTE_DROP`은 36.0%다. 5번째 세션(769번째 시행)에 능력이 급락하면 정착 시간이 기한 768을 넘는다. 정착 시간 중앙값은 1114번째 시행으로, 급락 뒤 다시 정착하는 데 창 길이 192를 포함해 약 346시행이 걸렸다. 과정 잡음을 작게 둔 필터는 구조상 급변에 느리게 반응한다(과정 잡음을 바꿔 비교한 실행은 없다). 혁신 누적합으로 급변을 검출하는 변형의 결과는 9.8절에 있다.
- `SH_SLOPE_X15`(86.8%)는 정밀도 조건 충족이 921명으로 줄었다. 변별 배율 1.5는 격자 한 칸의 로짓 변화가 1.5배가 되는 조건이다.
- `SH_KNOB_HETERO`(88.2%)와 `SH_MILD_P10`(93.7%)는 범위 상한 포화가 각각 34명, 25명이다. 포화 환자 수만으로는 실패 전체가 설명되지 않으며 나머지 원인은 분해하지 않았다.
- `SH_FATIGUE_X2`(90.2%)는 오정지가 288건, `SH_LATENCY_SLOW`(92.4%)는 129건으로 늘었다(기준 25건). 지연시간 분포가 레짐 필터의 가정에서 벗어난 두 조건에서 오정지가 늘었다는 것까지가 실측이고, 경로별 분해는 하지 않았다.
- `SH_PRACTICE_X3`(89.8%)는 MCI에서 436명으로 떨어졌다. 원인은 분해하지 않았다.

### 9.7 결함 주입과 프로토콜 사례

- 결함 주입: 필터 결함 40건이 모두 `FALLBACK`으로 전환됐고(`FALLBACK` 시행 6,467회) 감시기 위반은 0건이다. 결함을 넣은 코호트의 결합 성공은 956/1000으로, 결함이 없는 1차 실행(962명)보다 6명 적다. 결함을 받은 환자는 그 세션의 나머지를 계단법으로 보내고 다음 세션에서 사전 분포부터 다시 추정한다.
- 프로토콜 사례:

| 사례 | 수렴 | 실배치 판정 | 범위 표지 | 피로 정지 | 감시기 위반 | 합격 |
| --- | --- | --- | --- | --- | --- | --- |
| `CASE_UPWARD` | 예 | 수렴 | 없음 | 0회 | 0 | 합격 |
| `CASE_DOWNWARD` | 예 | 수렴 | 없음 | 0회 | 0 | 합격 |
| `CASE_FATIGUE_STOP` | 예 | 수렴 | 없음 | 1회 (지연 8시행) | 0 | 합격 |
| `CASE_FLOOR_UNREACHABLE` | 아니오 | 미수렴 | 하한 | 0회 | 0 | 합격 |
| `CASE_CEILING_UNREACHABLE` | 아니오 | 미수렴 | 상한 | 0회 | 0 | 합격 |

### 9.8 급변 검출 변형 (`VAR_CHANGE_DETECT`, 시드 162023)

| 코호트 | 검출 없음 (1차 정책) | 급변 검출 변형 | 변형의 재개방 횟수 (환자 수) |
| --- | --- | --- | --- |
| 기본 | 962/1000 (96.2%, 하한 0.9505) | 956/1000 (95.6%, 하한 0.9438) | 592 (450) |
| 급성 저하 `SH_ACUTE_DROP` | 360/1000 (36.0%) | 586/1000 (58.6%) | 1,457 (947) |

- 급성 저하 시나리오는 36.0%에서 58.6%로 올랐다. 여전히 95%에 못 미친다. 기한 안에 정착한 환자는 362명에서 590명으로 늘었다.
- 기본 코호트는 962명에서 956명으로 줄었다. 점추정은 95%를 넘지만 하한(0.9438)과 층별 게이트(EAD 94.8%)는 넘지 못한다. 급성 저하를 넣지 않은 기본 코호트에서도 재개방이 592회(환자 450명) 일어났다.
- 감시기 위반은 두 실행 모두 0건이다.
- 그래서 급변 검출은 1차 정책에 넣지 않았다. 이진 응답에서 급락 직후의 표준화 혁신 평균은 약 −0.23으로 작아, 오경보를 줄이면 검출이 늦어지고 검출을 당기면 기본 코호트의 정밀도가 떨어진다.

---

## 10. 요구사항 ↔ 하네스 검사 추적표

| 요구사항 | 설계 위치 | 하네스 근거 |
| --- | --- | --- |
| 다차원 잠재 능력, 피로, 학습 효과, 지연시간을 결합한 mIRT 생성 모형 | 2.3–2.5절 | `Env.step`, `EnvTests` (재현성, 노브별 단조성, 연속 오답 감점) |
| 코호트 모수 샘플링 규격 | 2.2절, 2.6절 | `sample_patient`, fixture `strata` 블록 |
| 칼만 필터 / BKT 상태 추정기 | 3장 | `Scheduler.observe`, `SchedulerTests` (빠른 경로와 느린 경로 일치, 갱신 방향, 공분산 대칭·양수) |
| 안전 제약형 컨텍스추얼 밴딧 제어 법칙 | 4장 | `Scheduler.act`, 절제 `ABL_NO_SAFETY` |
| 좌절 유발 연속 오답률 상한 | 4.3절, 5장, 7.2절 | `judge`의 좌절 사건 집계, 감시기 불변식 3·4 |
| 수렴 판정의 수학적 정의 | 7.1절 | `judge`, `JudgeTests` 8건 (경계값, 늦은 정착, 이탈 허용, 보호 구간, 진동) |
| 층화 1,000명 몬테카를로 | 8.1절 | `run_cohort`, `PRIMARY`와 반복 2회 |
| 분포 이동 스트레스 시험 | 8.4절 | `shifts` 14개 |
| 실패 안전 동작 | 5장 | 결함 주입, 프로토콜 사례 5건, `monitor.violations` |
| 공통 감사 프로토콜 16-2 행 | 8.5절 | `protocol_cases` |
| 급변 추종 | 3.4절 | `VAR_CHANGE_DETECT` 변형 두 실행, `SchedulerTests`의 검출 시험 |
| 독립 재계산 | 8.7절 | `cog16/audit.py` 관문 4개, `tests/test_cog16_audit.py`의 변조 검출 7건 |

---

## 11. 실제 요약 통계 반입 절차와 남은 항목

1. ADNI 영역별 합성 점수의 층별 평균·공분산과 DementiaBank 지연시간 요약을 DUA 구역 안에서 집계한다. 반출물은 2.6절 표의 모수 값뿐이다.
2. fixture의 `strata`와 `design` 해당 키를 바꾸고 잠금 해시를 다시 고정한다. 정책 설정(`controller`)은 개발 시드에서만 다시 맞춘다.
3. `python3 -B -m cog16.orchestrate --output evidence/cog16-run.json`을 실행하고 9장을 새 수치로 바꾼다.

이 구현에 없는 것:

- 함수형 불일치 시험. 정책의 모형과 응답 생성기가 같은 함수형(피로의 지수 포화, 학습의 지수 곡선과 같은 시상수, 오후 구간의 선형 경사)을 쓴다. 8.4절의 분포 이동은 모수만 옮기고 함수형은 그대로 둔다. 함수형이 다른 생성기에서의 수렴률은 측정하지 않았으므로 9장의 수치는 그만큼 낙관적일 수 있다.
- 오경보 비용 없이 급변을 따라가는 장치. 3.4절의 변형은 급성 저하 시나리오를 개선하지만 기본 코호트의 수렴률을 낮춘다(9.8절).
- 지연시간을 능력 추정에 쓰는 결합 갱신. 지금은 지연시간이 레짐 판별과 시간 초과 예측에만 들어간다.
- 등급 응답(부분 점수) 문항. 이진 응답보다 시행당 정보가 많아 7.5절의 하한을 낮출 수 있다.
- 피로·일중·부주의 모수의 실자료 근거. 공개 요약 통계로 식별되지 않아 가정으로 남아 있다.
- 6.2절 PyTorch 구현과 참조 구현의 동치 시험.

---

## 12. 참고 문헌

저자와 연도만 적는다. 원문 대조는 하지 않았다.

- Reckase (2009). 다차원 문항반응이론.
- van der Linden (2006, 2007). 응답 시간의 로그정규 모형과 속도–정확도 위계 모형.
- Corbett & Anderson (1994). 베이지안 지식 추적.
- Kaernbach (1991). 가중 상하 계단법.
- Clopper & Pearson (1934). 이항 비율의 정확 신뢰구간.
- IEC 62304:2006+A1:2015. 의료기기 소프트웨어 생명주기 프로세스.
