# V3.6 Runtime Harness State Machine (★ 회장 verbatim 2026-05-28 · spawn / watchdog / closeout 상태기계)

- 작성: 2026-05-28 14:35 KST · ANU chair-facing session
- 분류: **read-only design packet** (구현 dispatch 0)
- 상위: [[v36_runtime_harness_control_plane]] layer 2 + 3 + 4 의 상태기계 분리 문서

---

## 1. Spawn Detection State Machine (layer 2)

### 1.1 9 state 정의 (회장 verbatim)

```
NOT_REGISTERED
  └─ schedule_id 미발급 또는 cron-list 부재 + history 부재 + timer 부재

REGISTERED
  └─ schedule_id 등록 확인 + timer 등록 (★ DISPATCHED_SUBMITTED_UNVERIFIED 동의어)
  └─ ★ dispatch.py status:ok 만으론 본 state 진입 불충분 — schedule_id 실제 등록 evidence 필요

FIRED
  └─ schedule fire_time 도래 + cron-history 또는 schedule_history 진입
  └─ ★ schedule_history 부재만으론 FIRED 부정 단정 불가 (signal optionality)

SESSION_SEEN
  └─ 별도 system_prompt path 의 봇 claude 프로세스 관측
  └─ ★ system_prompt hex 가 ANU 세션 hex 와 다름이 확정 신호

WORK_STARTED
  └─ 봇 worktree 생성 또는 events_dir 첫 봇 write 마커 생성
  └─ ★ dispatch marker (layer 1) 가 본 state 진입의 자동 트리거

ARTIFACT_SEEN
  └─ code/test/report 등 봇 산출물 mtime 신규 변동

CALLBACK_REGISTERED
  └─ 봇이 ANU-key cron 등록 (collector_role=ANU verified)
  └─ ★ self-key 등록 = NON_AUTHORITATIVE (별도 분류 · [[feedback_callback_self_key_helper_not_wired_260521]])

DONE
  └─ .done + .done.notified + .anu-notified 3 마커 + task-timers 종결

UNKNOWN
  └─ 위 8 신호 어느 것도 명확히 진단 불가
  └─ ★ false-negative 방지선 — "spawn 0" 단정 금지 · 다음 sample 까지 polling 또는 chair 보고
```

### 1.2 transition diagram

```
                    ┌─→ UNKNOWN ←─ (any state ↔ UNKNOWN: signal loss 시)
                    │
NOT_REGISTERED ──→ REGISTERED ──→ FIRED ──→ SESSION_SEEN ──→ WORK_STARTED
                                                                  │
                                                                  ↓
                                                            ARTIFACT_SEEN
                                                                  │
                                                                  ↓
                                                       CALLBACK_REGISTERED
                                                                  │
                                                                  ↓
                                                                 DONE

★ 역행 금지 — UNKNOWN 외 어떤 state 도 자동 후퇴 안 함
★ 분기 가능 — FIRED → SESSION_SEEN 없이 ARTIFACT_SEEN 도 가능 (봇이 worktree 안 만들고 main repo read-only 진단 case)
```

### 1.3 신호 → state 매핑 (★ 최소 2 신호 OR weighted)

- `REGISTERED` 진입: timer 등록 + schedule_id 등록 (2 신호)
- `FIRED` 진입: fire_time 도래 + (cron-history OR schedule_history) (2 신호)
- `SESSION_SEEN` 진입: system_prompt path 별개 + process active (2 신호)
- `WORK_STARTED` 진입: dispatch marker + (artifact_mtime 변동 OR worktree 생성) (2 신호)
- `ARTIFACT_SEEN` 진입: code/test/report mtime < 900s (1 신호 충분)
- `CALLBACK_REGISTERED` 진입: ANU-key cron 등록 evidence + envelope sha (2 신호)
- `DONE` 진입: .done + task-timers 종결 (2 신호)
- `UNKNOWN` 진입: 전이 신호 부족 또는 충돌

### 1.4 ★ task-2703 적용 trace (역사적 정정)

```
13:22:33 [REGISTERED]        — BE5161A0 cron id 등록 · task-timers running
13:22:43 [FIRED]             — fire_time 도래 (단 schedule_history 부재 → UNKNOWN 진단됐었음)
13:26    [SESSION_SEEN]      — PID 4105498 별도 system_prompt 18b3a030fdc880ae
13:26~   [WORK_STARTED]      — 단 dispatch marker 미생성으로 events_dir 진입 신호 부재
13:52    [ARTIFACT_SEEN]     — harness-mvp-active.json + 산출물 mtime
14:09    [CALLBACK_REGISTERED] — ANU-key cron + envelope
14:09    [DONE]              — .done + 3 마커 + task-timers completed

★ ANU 실측 시점 ~13:29 ~13:31 ~13:35 → "spawn 0" 단정 = grep -v cokacdir 필터 버그로 SESSION_SEEN 신호 false-negative
★ 본 state machine 적용 시 동일 시점 = UNKNOWN (REGISTERED→FIRED 후 SESSION_SEEN 신호 unclear) → 다음 sample 까지 polling · 단정 금지
```

---

## 2. Watchdog Decision State Machine (layer 3)

### 2.1 state 정의

```
QUIET           — 마지막 N cycle 동안 alert 발사 0 + alive 신호 유지
WATCH           — alive 신호 일부 결손 + ev_age 증가 추세 (★ INFO 로그만)
ALERT_INFO      — silently_stalled 후보 1 cycle (★ 로그만 · chair chat 0)
ALERT_WARN      — silently_stalled 2 cycle 연속 (★ 로그 + 다음 cycle 재확인 · chair chat 0)
ESCALATE_CHAIR  — Critical 7 분류 OR 회장 명시 escalate OR 본인 정책 위반 + 2 cycle 연속 silently_stalled (★ chair chat sendMessage 허용)
SUPPRESSED      — .escalate / .escalate.acked 마커 존재 (★ 회장 task-2405 fix#A 메커니즘 보존)
```

### 2.2 transition

```
QUIET ──(alive 신호 일부 결손)──→ WATCH
WATCH ──(silently_stalled 발견)──→ ALERT_INFO
ALERT_INFO ──(다음 cycle 동일)──→ ALERT_WARN
ALERT_WARN ──(Critical 7 OR 회장 명시)──→ ESCALATE_CHAIR
ALERT_WARN ──(alive 신호 회복)──→ WATCH ──(완전 회복)──→ QUIET

* ──(.escalate 발견)──→ SUPPRESSED  (★ 임의 state 에서 즉시 진입)
SUPPRESSED ──(.escalate.acked 또는 task DONE)──→ QUIET
```

### 2.3 alive 신호 OR 집합 (회장 verbatim 영역 #2)

- dispatch marker 존재 (`<task_id>.dispatched-*`)
- closeout marker 존재 (`<task_id>.harness-mvp-active*` / `<task_id>.*active.json`)
- escalate 마커 존재 (`<task_id>.escalate*`)
- spawn detection state ≥ `WORK_STARTED`
- bot session process active
- worktree mtime < 900s
- recent artifact mtime < 900s

→ 위 OR 집합 1 이상 참 → `alive` → QUIET 또는 WATCH

### 2.4 chat sendMessage 허용 조건 (★ 본 contract 의 핵심 게이트)

- 오직 `ESCALATE_CHAIR` 진입 시에만 chat sendMessage 발사
- `ALERT_INFO` / `ALERT_WARN` / `WATCH` / `QUIET` / `SUPPRESSED` 는 chat 발사 0
- ★ task-2703 #3 incident: alert-only(ALERT_INFO 동의어) 가 chat 발사 = 본 contract 위반. 본 contract 적용 시 ESCALATE_CHAIR 진입 0 → chat 발사 0

### 2.5 ★ task-2703 #3 적용 trace (정정)

```
13:42 [ALERT_INFO]       — ev_age=-1 (false signal · dispatch marker 부재) + chair chat 0 (★ 본 contract)
13:44 [ALERT_WARN]       — 2 cycle 연속 + chair chat 0
13:46~13:50 [ALERT_WARN] — silently_stalled 지속 + chair chat 0 (Critical 7 아님 + 회장 명시 escalate 아님)
13:52 [WATCH]            — closeout marker 생성 → alive 신호 회복
13:54 [QUIET]            — "알람 없음 (false alert 0건 확인)"

★ 본 contract 적용 시 chair chat 6회 발사 = 0회로 감소
```

---

## 3. Closeout/Callback State Machine (layer 4)

### 3.1 state 정의 (회장 verbatim 영역 #5)

```
WORK_CLOSEOUT_STARTED  — 봇이 첫 closeout marker 생성
FINISH_IN_PROGRESS     — finish-task.sh 호출 + G3/G4 게이트 진행 + .callback-* 마커 생성 중
CALLBACK_LAUNCHED      — 봇이 ANU-key cron 등록 (envelope sha 박제)
DONE                   — .done + .done.notified + .anu-notified + task-timers 종결
ANU_RECEIVED           — ANU 세션이 본 task 의 result_path/report_path 능동 회수 (★ 본 state 강제)
CHAIR_REPORTED         — ANU 가 회장에게 종합 보고 (★ 본 state 강제 · 자가 closeout 단정 금지)
```

### 3.2 transition

```
WORK_CLOSEOUT_STARTED ──→ FINISH_IN_PROGRESS ──→ CALLBACK_LAUNCHED ──→ DONE
                                                                       │
                                                                       ↓
                                                              ANU_RECEIVED
                                                                       │
                                                                       ↓
                                                              CHAIR_REPORTED
```

### 3.3 회수 우선순위 3 경로

1. **normal callback** (★ 1순위 · 봇 ANU-key cron) — CALLBACK_LAUNCHED → ANU 세션 spawn → ANU_RECEIVED
2. **closeout marker watcher** (★ 2순위 · file event-driven) — WORK_CLOSEOUT_STARTED 시점에 ANU 에 즉시 signal → ANU_RECEIVED
3. **fallback safety-net** (★ 3순위 · N분 후 cron) — normal + watcher 모두 미작동 시 ANU read-only 회수

### 3.4 ★ ANU 능동 회수 의무 강제

- DONE state 도달 후 N분 (제안 default: 5분) 내 ANU_RECEIVED 진입 강제
- 미진입 시 watchdog 이 별도 alert (`ANU_RECEPTION_DELAY`) → chair 보고 (ESCALATE_CHAIR)
- CHAIR_REPORTED 진입 = ANU 가 회장에게 봇 결과 + DoD + evidence 종합 보고 완료

### 3.5 ★ task-2703 trace (정정 vs 실제)

```
13:52 [WORK_CLOSEOUT_STARTED] — harness-mvp-active.json
14:04~14:09 [FINISH_IN_PROGRESS] — escalate / callback-cause / callback-launch / completion.txt
14:09 [CALLBACK_LAUNCHED]     — ANU-key cron 발사
14:09 [DONE]                  — .done + 3 마커 + task-timers completed

★ 본 contract 기준: ANU_RECEIVED ≤ 14:14 (DONE+5min) 진입 강제 + CHAIR_REPORTED 즉시 후속
★ 실제: ANU 인지 ~14:00 (회장 사진) → ~14:08 incident report → 14:38 정정 보고
   → ANU_RECEIVED 시점 ANU가 13:52 WORK_CLOSEOUT_STARTED 부터 인지 못함 (closeout marker watcher 미구현)
   → ★ 본 contract 의 2순위 (marker watcher) 강제 시 13:52 즉시 ANU signal → ~10분 지연 0
```

---

## 4. 상태기계 통합 — 한 task 의 life-cycle

```
Spawn:        NOT_REGISTERED → REGISTERED → FIRED → SESSION_SEEN → WORK_STARTED → ARTIFACT_SEEN → CALLBACK_REGISTERED → DONE
Watchdog:     QUIET → WATCH ↔ ALERT_INFO ↔ ALERT_WARN ↔ ESCALATE_CHAIR (또는 SUPPRESSED) → QUIET
Closeout:     WORK_CLOSEOUT_STARTED → FINISH_IN_PROGRESS → CALLBACK_LAUNCHED → DONE → ANU_RECEIVED → CHAIR_REPORTED

★ Spawn `DONE` ↔ Closeout `DONE` 동일 시점
★ Watchdog 은 Spawn/Closeout state 를 alive 신호로 소비
★ Closeout 의 ANU_RECEIVED / CHAIR_REPORTED 는 ANU 본체 의무 — 봇 책임 외
```

---

## 5. 본 state machine 의 단일 효력

- 본 문서는 **설계** — 구현 dispatch 0 · 코드 0
- 본 state 정의는 [[v36_runtime_harness_control_plane]] layer 2 + 3 + 4 와 동등
- 구현은 회장 결정 + chair_authorization_id verbatim + 우선순위 별 별도 task 로만

★ 회장 verbatim 2026-05-28. 9 spawn state · 6 watchdog state · 6 closeout state. 단정 금지 (UNKNOWN 강제) · chat sendMessage gate (ESCALATE_CHAIR 한정) · ANU 능동 회수 의무 (ANU_RECEIVED + CHAIR_REPORTED).

끝
