# v0.1.230 — 36th Stable Seal (PlayerPrefs SSOT 정합성 마무리)

**날짜**: 2026-05-17
**범위**: v0.1.229 ~ v0.1.230 2 사이클
**Ribbon 8 탭 명령 누계**: 45 (35th seal 45 -> 36th seal 45, ±0 — 폴리시/cleanup 사이클)

## 사이클별 변경

### v0.1.229 — Status 라벨 active View slot 표시

- `_activeViewSlot` 필드 (0 = 없음, 1~5 = 마지막 Save/Load slot)
- SaveViewSlot / LoadViewSlot -> 즉시 `UpdateStatusLabel()` 호출 + slotN 트래킹
- production status 라벨 우측에 `View:[N]` 분기 (활성 slot > 0 일 때만 출력)
- 시작 시 0 -> 비표시 (사용자가 명시적으로 Save/Load 클릭한 후에만 라벨 노출)

### v0.1.230 — PlayerPrefs SSOT audit + cleanup

전수 grep으로 PlayerPrefs 키 12종 매핑:

| 키 | 형식 | 용도 | 상태 |
|---|---|---|---|
| `factory00.recent_files` | `|` separator string | 최근 .twn 5개 | OK |
| `factory00.view_slot1` ~ `5` | JsonUtility ToJson(ViewState) | 카메라 프리셋 | OK |
| `factory00.lit_mode` | int 0/1 | Lit 토글 | OK (LitModePref const) |
| `factory00.auto_tracking_scroll` | int 0/1 | Auto Tracking | OK |
| `factory00.screen_resolution` | string `WxH` | 시작 해상도 | OK (ResolutionPref const) |
| `factory00.parts_section_height` | float | 좌측 splitter | OK |
| `factory00.inspector_section_height` | float | Inspector splitter | OK |
| `factory00.left_panel_width` | float | 좌측 패널 width | OK |
| `factory00.gizmo_visible` | int 0/1 | Gizmo 가시성 | OK |
| `factory00.help_seen` | int 0/1 | Welcome 토스트 1회성 | OK |
| `factory00.parts_rows_height` | float | (.twn 직렬화 전용) | **죽은 키 -> fix** |
| `factory00.inspector_height` | float | (.twn 직렬화 전용) | **죽은 키 -> fix** |
| `factory00.license.tier` | int | License | **컨벤션 위반** (period 사용) |

#### 처리한 결함

1. **`parts_rows_height` / `inspector_height` 죽은 키**
   - READ-only 패턴 — SetFloat 호출 0건
   - .twn TwnViewSettings 직렬화 시 항상 0f -> 무용 데이터
   - **fix**: 실 splitter 키와 sync (`parts_section_height` / `inspector_section_height`로 변경)
   - 이후 .twn 저장 시 의미있는 값 직렬화

2. **`ViewSlot1Pref` const 미참조**
   - v0.1.227 호환 보존 목적이었으나 `ViewSlotPrefix + "1"` 동일 키 생성으로 호환 자동 보장
   - **fix**: const 제거, 호환 주석은 `ViewSlotPrefix` 위치로 통합

3. **`factory00.license.tier` 컨벤션 위반**
   - 다른 키는 underscore (`_`) 만 사용 (`factory00.parts_section_height`)
   - 본 키만 period (`.tier`) 사용 — 컨벤션 불일치
   - **처리**: 마이그레이션 위험 (기존 사용자 라이센스 키 데이터 영향) -> 보고만, 변경 X
   - 추후 키 마이그레이션 사이클 시 일괄 처리 권장

## 핵심 패턴 SSOT 강화

### PlayerPrefs 키 컨벤션 (v0.1.230 정합성 마무리)

```
factory00.<feature>_<descriptor>   <- underscore 만, period 금지
예외: factory00.license.tier (legacy, 보고만)
```

### .twn 직렬화 ↔ PlayerPrefs sync

| .twn 필드 | PlayerPrefs 키 |
|---|---|
| TwnViewSettings.partsRowsHeight | `factory00.parts_section_height` (v0.1.230~) |
| TwnViewSettings.inspectorHeight | `factory00.inspector_section_height` (v0.1.230~) |
| TwnViewSettings.litMode | (PlayerPrefs 우회, `_litMode` 필드 직접 sync) |
| TwnViewSettings.bboxOn | (PlayerPrefs 우회, `_bboxEnabled` 필드) |
| TwnViewSettings.gizmoOn | `factory00.gizmo_visible` |
| TwnViewSettings.autoTrackingScroll | `factory00.auto_tracking_scroll` |

## Ribbon 8 탭 명령 — 45 (변동 없음)

| 탭 | 명령 수 |
|---|---|
| File | 6 |
| Edit | 6 |
| View | 12 |
| Model | 8 |
| Simulation | 4 |
| Communication | 3 |
| Review | 5 |
| Present | 2 |
| **총계** | **45** |

## 협업자 spec 매칭

- 진척 변동 없음 (23/28 = 82%)
- 본 봉인은 폴리시·정합성 cleanup 중심 — 신규 spec 항목 없음

## 외부 URL

- stable: https://os-file-server.tail2b816d.ts.net/downloads/factory00-windows-x64-v0.1.230-playerprefs-audit-stable.zip
- 갤러리: https://os-file-server.tail2b816d.ts.net/latest-builds.html#v0.1.230

## 다음 사이클 큐

- v0.1.231+ View slot 컨텍스트 메뉴 우클릭 "삭제" 항목 (작은 UX 폴리시)
- v0.1.232+ Edit Duplicate (Part Mesh/Material 복제 매트릭스 — spec 필요)
- v0.1.233+ Communication MX Component placeholder 갱신 (SDK 대기)
- license.tier 키 마이그레이션 (legacy -> underscore 컨벤션 통일 — 시간 여유 시)
- task #39 InspectorVM / MotorTableVM 분리 (Bootstrap -500~700 라인)
