# 큰 오프라인 배포본과 독립 진입점

계약: **OFFLINE-FULL-01**. 현재는 구현·격리 검증 후보이며 설치/현장 수용 완료가 아니다.
`ct-offline`은 기존 `ct`를 먼저 교체하지 않는 별도 도구다. 이번 적용 adapter는 승인된 test의
Compose backend에 한정된다. 서버 정의 없는 구형/transaction 설치는 정보 수집만 하고 적용을 막는다.

## 무엇이 달라지는가

- 준비 장소에서 완성 image를 만들어 반입한다. 현장 build, 인터넷 pull, Git, pip/apt 설치가 필요하지 않은 경로다.
- 현장 OS, DB, 영상, 인증정보를 새로 설치하거나 지우는 작업이 아니다.
- 대상/기반 image를 정확히 고정한다. 큰 패키지라고 다른 서버에도 무조건 적용할 수 있는 것은 아니다.
- Analytics image와 FIGHT/FALL 선택·필요한 표시 정책만 변경한다. 그 외 서비스 image·모델·ROI 운영 모드와 채널 On/Off는 보존한다.
- FIGHT R5/FALL R2, 기존 높은 score와 cooldown은 유지한다. 유효한 낮은 score만 사람0.25/관절0.10 하한을 적용한다.
- FIGHT 표시3초는 Web Start/reset과 분리한 AI 정책이다. 현재 대응이 없으면 옛bbox를 유지하지 않는다.
- 기존ct 설치 파일/launcher를 자동 덮어쓰지 않는다. 새 도구는 검증한 로컬 staging에서 사용한다.

## 운반과 첫 사용

1. 담당자가 **봉인 완료**라고 확인한 배포 폴더와 별도 신뢰 경로의 manifest SHA256를 받는다.
   `PREVIEW`, `UNSEALED`, `BLOCKED` 자료는 실제 설치에 사용하지 않는다.
2. Windows에 다운로드하고 USB의 새 전용 폴더로 복사한다. 기존 USB 자료와 다른 폴더는 그대로 둔다.
3. 큰 파일 제한이 있으면 담당자가 검증한 분할본을 이용한다. 임의 포맷·강제 파일시스템 변경을 하지 않는다.
4. 아래는 **명령 형식 설명**이다. 실제 패키지 경로·SHA가 채워진 안내를 사용한다.

```text
python3 /반입폴더/ct-offline inventory
python3 /반입폴더/ct-offline verify --package /반입폴더 --sha256 승인된지문
sudo python3 /반입폴더/ct-offline stage --package /반입폴더 --sha256 승인된지문 --destination /data/contextra-offline/새버전
```

Windows에서는 기존 `Get-FileHash -Algorithm SHA256`으로 전달받은 archive/manifest를 대조한다.
USB 옆 checksum 파일만 일치한다고 배포자 신원이 인증되는 것은 아니다. 패키지를 검증 없이 실행하지 않는다.
Linux에서는 `python3 ct-offline`로 실행하므로 Windows/USB의 executable bit에 의존하지 않는다.
staging은 root 전용 폴더이며 상위 폴더도 타 계정이 변경할 수 없어야 한다.
`/data`라는 이름만으로 충분한 용량이나 로컬 디스크임을 단정하지 말고 사전검사 결과를 확인한다.

## 진행 순서

| 단계 | 사용자 행동 | 변경/판단 |
| --- | --- | --- |
| 서버 확인 | inventory | 읽기만 수행. 실제 서버·backend·서비스 확인 |
| 파일 검사 | verify | 승인 manifest와 모든 파일 지문 대조 |
| 로컬 반입 | stage | USB에서 서버의 새 폴더로 복사·재검증. 운영 변경 없음 |
| 준비 기록 | prepare / PREPARE | 현재 기준과 로컬 작업 기록 생성. 서비스 변경 없음 |
| 유지보수 정지 | 기존ct의 정상 Stop 절차 | 사용자가 채널 정리와 서비스 정지를 수행. 정상 정지가 아니면 적용 금지 |
| 적용 | apply / APPLY | image 반입, 설정안·복귀본 생성, CAS 반영, Analytics 재생성, 준비 확인 후 Gateway 복구 |
| 사용자 확인 | test Web의 선택 시험 채널 | 사용자가 Start/Stop·표시·알람·썸네일·클립 확인 |
| 반출 | export / EXPORT | 비민감 요약·진단을 선택 폴더에 내보냄 |

apply/resume/rollback은 명시적 변경 명령이다. 서비스가 실행 중이면 자동 Stop하지 않고 차단한다.
기존 `ct patch apply`는 도구/source 반영이며, 이 전체 Runtime 적용과 같은 명령이 아니다.
패키지의 기본 준비 상태만으로 복귀본 생성이 끝났다고 보지 않는다. STAGED 단계에서 쓰기 전 복귀본을 확보한다.
설정 파일을 원자적으로 바꾸므로 개별 파일 bind도 Analytics를 다시 만들어 현재 파일을 보게 한다.
네트워크/SSH/NIC/firewall 규칙을 변경하지 않는다. 내부망 Web/영상 통신은 유지한다.

## 중단·복귀

- 화면의 마지막 상태와 로컬 기록 경로를 먼저 확인한다. 같은 명령을 무조건 반복하지 않는다.
- `resume`은 명시적 재개다. 소유 파일이 이전/후보 중 어느 상태인지 대조하고 사용자 변경은 덮지 않는다.
- `rollback`은 기존ct로 정상 정지를 마친 뒤 `RESTORE`로 선택한다.
  이전 image·이번 변경 설정·실행 기준을 복구하고 실제 서비스 준비를 확인한다.
- 도구/입력 기록만 돌아갔다고 Runtime 복귀 완료라 하지 않는다. DB·영상·인증정보는 과거로 되돌리지 않는다.
- 이전 image가 없거나 이후 설정 수정과 충돌하면 자동복구하지 않는다. 코드/데이터 역호환이 없는 경우도 별도 검토다.
- 중간 `apply-pending.json`은 기존ct의 우발적 Start를 막는 소유 표시다. 손으로 삭제하거나 예전ct의 config restore에 넘기지 않는다.
- 새 도구가 손상되면 보관한 동일 승인 패키지의 독립 진입점을 사용한다. 기존 도구와 정상 image는 삭제하지 않는다.
- VERIFIED/ROLLED_BACK은 AI process 준비 확인이다. 브라우저/알람 수용과 장시간 안정성은 별도다.
- 이미 반입한 image는 ID 확인 후 재사용한다. 이는 cold image load를 실제로 시험했다는 뜻이 아니다.

## 기록 반출과 사용자 피드백

모든 명령은 로컬 attempt 기록을 남긴다. 적용 원장은 서버 정의의 state 아래 `offline/<release-id>`다.
민감 설정의 복귀본은 로컬 root 전용 `private`에만 보관하며 반출하지 않는다.
패키지 검사 실패나 구버전 정보 부족에도 `export --record 기록폴더 --destination 반출폴더`를 사용할 수 있다.
USB 쓰기는 EXPORT 확인 후 선택 폴더 아래 새 이름으로만 수행한다. 기존 파일/폴더를 동기화·삭제하지 않는다.
USB가 읽기 전용/분리/가득 참이면 반출 실패로 표시하고 로컬 기록은 남는다. 강제 remount나 포맷은 없다.

반출물: `SUMMARY.ko.md`, `result.json`, `SHA256.json`.
패키지/도구 버전·단계·오류 code·명령 종료 분류·image·readiness를 포함한다.
비밀번호/token/인증 URI/개인키/전체 shell history/임의 stdout은 수집·반출하지 않는다.
로컬 디스크/권한 때문에 기록 자체가 실패하면 `LOG_WRITE_FAILED`를 보고 중단한다.

원래 결과를 수정하지 말고 별도 `USER_FEEDBACK.md`에 다음을 적는다. 비밀값은 넣지 않는다.

```text
사례/작업ID:
종류: 도구 UX / 안내서 / 기술 오류 / 설명 혼동
실행 단계와 대략적 시각:
예상했던 결과:
실제로 본 결과와 불편한 점:
```

분석자는 반출물만으로 먼저 판단하고, 이후 test 직접 조회와 비교한다.
부족했던 정보를 다음 로그 계약에 반영하며 사용자 피드백→근거→원인→수정 버전→재확인을 연결한다.
공통 절차는 이 문서, 실행별 결과는 profile run, 반복 문제는 같은 사례ID로 연결한다.
다음 배포에는 바뀐 대상·실제 기준·허용 중단·적용 승인만 새로 확인한다.

## 준비 환경의 알려진 제약

- `docker save`는 최종 출력이 `/data`여도 Docker root의 임시 공간을 사용한다.
  출력 용량만 검사하지 않는다. 이전/후보 image의 중복 층을 고려한 임시 예산과15GiB 여유를 먼저 검사한다.
- 처음 발견한 image layer 제한은 기존 마지막 층의 정확한 파일을 보존해 재구성하는 방법으로 해결했다.
  임의 flatten/prune/기반환경 교체로 우회하지 않는다.
- 새 배포 도구는 commit으로 출처가 고정돼야 봉인한다. 미커밋 snapshot을 자동 승인하지 않는다.
- 청계산의 마지막 보관 상태와 실제 현장 상태는 다르다. 이번 test 후보를 현장용 완성본으로 표시하지 않는다.
- 사용자에게 의도적 실패 훈련을 요구하지 않는다. 정상 적용을 먼저 수용한 뒤 별도 요청으로 확장한다.
