# 사용자 수동 적용 절차

검토: @DATE@ KST. 아래 명령은 **test에서 사용자가 직접 실행**한다.
현재 상태는 준비 완료이며 Codex는 적용하지 않았다. 모든 단계가 성공한 뒤 다음 단계로 넘어간다.

## 1. Windows와 USB

`Contextra_Offline_USB_20261103_r01` 전체를 새 폴더로 복사한다.
USB 기존 자료는 유지한다. 128GB 이상, 여유70GiB 이상, 큰 파일 지원 여부를 확인한다.
FAT32나 복사 오류가 있으면 중단한다. 자동 포맷/동기화/삭제는 하지 않는다.

Windows PowerShell에서 복사된 폴더로 이동한 뒤 다음으로 작은 검사목록의 지문을 본다.
결과를 **최종 채팅에서 받은 지문**과 비교한다. 경로는 탐색기의 실제 폴더를 사용한다.

```powershell
Get-FileHash -LiteralPath .\BOOTSTRAP_SHA256SUMS -Algorithm SHA256
```

이 단계만으로 image 전송 검증이 완료된 것은 아니다. Linux의 전체 검사까지 필요하다.

## 2. test와 USB 장치 확인

test 터미널에서 읽기만 수행한다. 기존 SSH 연결은 유지한다.

```bash
hostname
lsblk -o NAME,SIZE,FSTYPE,LABEL,UUID,MOUNTPOINTS
df -h / /data
```

USB 연결 전후 목록에서 새 장치를 확인한다. `/dev/sda`, `/dev/sdb`를 USB로 추측하지 않는다.
test는 VM이므로 장치가 안 보이면 VM 관리 화면에서 USB 전달부터 확인한다.
이미 마운트돼 있으면 재마운트하지 않는다. 마운트되지 않았다면 장치가 확실할 때만
직접 선택한 새 mountpoint에 `ro,nosuid,nodev,noexec`로 읽기 전용 마운트한다.
이번 안내에서 장치명을 지정하거나 디스크를 포맷하지 않는다.

## 3. 코드 실행 전 무결성 확인

터미널에서 USB 안의 `Contextra_Offline_USB_20261103_r01` 폴더로 이동한 뒤 아래를 실행한다.
`read` 질문에는 최종 채팅에서 받은64자리 bootstrap 지문을 붙여 넣는다.

```bash
read -r -p '별도로 받은 BOOTSTRAP_SHA256SUMS 지문: ' TRUSTED
printf '%s  BOOTSTRAP_SHA256SUMS\n' "$TRUSTED" | sha256sum -c -
```

`OK`를 확인한 뒤에만 다음을 실행한다. 하나라도 실패하면 package 코드를 실행하지 않는다.

```bash
sha256sum -c BOOTSTRAP_SHA256SUMS
```

이 검사는 진입점·Python source·안내서·manifest·전체 image 검사목록을 확인한다.
큰 image는 다음 stage에서 전체 검사한다. standalone `verify`를 추가해도 되지만
동일한 대형 파일을 또 읽으므로 필수 단계는 아니다.

## 4. 대상 확인과 서버 반입: 서비스 유지

위 검사가 모두 성공한 동일 터미널에서 실행한다.

```bash
DELIVERY="$(pwd -P)"
PKG="$DELIVERY/package"
DIGEST="$(awk '{print $1}' PACKAGE_SHA256.txt)"
STAGE=/data/contextra-offline/test-demo-20261103-r02
sudo env PYTHONDONTWRITEBYTECODE=1 python3 "$PKG/ct-offline" inventory
```

정상 기대: `contextra-local`, `compose`, 승인된 Contextra5개 서비스.
서버 정의 없음/다른 backend/다른 서버면 중단한다. 이름만 같은 다른 서버도 적용하지 않는다.
이 명령은 서비스 변경 없이 로컬 감사 기록을 남긴다.

```bash
sudo env PYTHONDONTWRITEBYTECODE=1 python3 "$PKG/ct-offline" stage \
  --package "$PKG" --sha256 "$DIGEST" --destination "$STAGE"
```

`stage`는 image를 포함한 입력 검사·로컬 복사·출력 검사를 한다.
현재 구현은 CLI/복사 전 입력 검사와 출력 검사로 전체 해시를3회 읽고1회 복사한다.
이번 test 준비에서는 전체 해시1회가 약12~13분이었다. USB 속도에 따라 stage가1시간 이상 걸릴 수 있다.
진행률이 계속 출력되는 도구는 아니므로 한동안 출력이 없다는 이유만으로 실패로 판단하지 않는다.
검사 중 창을 닫거나 같은 stage를 중복 실행하지 않는다. 기존 staging이 있으면 덮어쓰지 않고 차단한다.
완료 시 경로가 `/data/contextra-offline/test-demo-20261103-r02`로 표시된다.
운영 image/설정/채널은 아직 변경되지 않는다.

staging 완료 후 USB는 안전하게 분리할 수 있다. 이후 package 실행은 서버 staging을 사용한다.
USB 안내서/별도 지문은 보관한다. 작업 로그는 서버 로컬에 계속 남는다.

## 5. 준비 기록과 변경 전 확인: 아직 서비스 유지

```bash
sudo env PYTHONDONTWRITEBYTECODE=1 python3 "$STAGE/ct-offline" prepare \
  --package "$STAGE" --sha256 "$DIGEST"
```

대상/설명을 읽고 `PREPARE`를 입력한다. 정상 상태는 `PREPARED`다.
이때는 현재 기준을 기록한 것이며, 실제 설정 복귀본은 apply의 STAGED 단계에서 변경 전에 확보한다.

다음을 확인하지 못했으면 **정지하지 말고 중단**한다.

- 현재 test Web/이벤트 목적지가 실제 test용인가. 다른 현장/아이서티 목적지면 적용하지 않는다.
  준비 중 읽은 설정은 알려진 아이서티 주소와 달랐지만 그것만으로 test 목적지를 확정하지 않았다.
- 이전 정상 image가 보존돼 있고 지원하는 현재 transaction은 `artifact-test-r02`인가.
- root 여유15GiB 이상, 기존 Contextra 서비스가 정상인가.
- 패키지 준비 후 운영 설정/소스가 바뀌지 않았는가. 변경 시 보호 차단을 우회하지 않는다.
- Contextra 일시 중단과 전체 해시검사 시간을 확보했는가. SSIMS는 정지 대상이 아니다.

## 6. 사용자가 Contextra만 정상 정지 후 적용

**여기부터 운영 변경이다.** 기존ct의 정상 정지를 사용한다.

```bash
sudo /usr/local/bin/ct stop
```

강제 종료/정지 실패/오류가 있으면 apply하지 말고 기록을 보존한다.
Docker daemon, SSIMS, 네트워크를 정지하지 않는다. 광범위한 `docker stop` 명령도 사용하지 않는다.
정상 정지한 뒤:

```bash
sudo env PYTHONDONTWRITEBYTECODE=1 python3 "$STAGE/ct-offline" apply \
  --package "$STAGE" --sha256 "$DIGEST"
```

설명을 읽고 `APPLY`를 입력한다. 이 확인 질문 전에도 전체 해시1회가 있어 시간이 걸릴 수 있다.
현재 구현에서는 정상 정지 뒤 apply 검증을 기다리는 시간도 Contextra 중단 시간에 포함된다.
image ID가 이미 있으면 load를 생략한다. 실제 image/설정 전환과 Analytics 재생성 후
의존 서비스 준비를 확인하고 마지막으로 Gateway를 복구한다. 채널 Start를 별도로 호출하지 않는다.
정상 기대는 `VERIFIED`, `process_ready: true`, `browser/event_media: USER_PENDING`다.

Web이 주기적으로 Start를 보내면 Gateway 복구 후 채널이 다시 실행될 수 있다.
이를 회수 실패로 보고 반복 Stop하지 않는다. 서비스 상태를 사용자가 확인한다.

## 7. 사용자 브라우저 확인과 기록

- test에 연결된 선택 시험 채널에서 영상/실시간 표시/알람/썸네일/클립을 직접 확인한다.
- FIGHT 빨강은 현재 충족 또는 최대3초 대응 유지, FALL 빨강은 현재 충족 또는 최대1초 대응 유지다.
- 빨강 유지와 새 Event는 다르다. 재무장2초와 채널별 cooldown도 별개다.
- `VERIFIED`나 HTTP 성공을 브라우저 수용/장시간10FPS 보장으로 해석하지 않는다.
- camera6/8/9 탑뷰·군중 한계와 엔진 고도화 보류는 그대로다.

문제가 있으면 [복구·반출 안내](02_RECOVERY_AND_LOGS.ko.md)에 따라 실패 상태부터 보존한다.
동일 명령 반복·채널 강제 Start·Event 재전송·설정 초기화로 우회하지 않는다.
사용자가 확인한 결과는 [피드백](03_FEEDBACK.ko.md)에 별도 기록한다.
