# 첫 FULL 배포 준비와 승인 경계

## 현재 완료 범위

배포 후보를 task worktree에 통합하고 최초 설치 재개, 모델 노출 범위, 진단 출력을 보완했다.
FULL 준비 완료는 공유물의 `FULL-MANIFEST.json`, `FULL-SHA256SUMS`와 실제 archive 검증으로
판단한다. 초기 `PREPARATION-MANIFEST.json`과 pending spec은 선행 준비 기록이며 설치용이 아니다.
소스·ONNX·private 초안 또는 image tar의 존재만으로 현장 설치가 끝났다고 판단하지 않는다.
FULL은 gzip level1로 준비 시간을 줄이고 CONFIG/APP은 기존 level9를 유지한다. 해제 형식과
파일별 hash/경로/권한 검증은 동일하다. 대상 GPU 변환·설치·연동 수용은 별도 승인 단계다.

## Export 임시 저장소

Docker save는 출력 폴더와 별개로 daemon 임시 경로를 사용한다. 준비 서버에서는 승인된
유지보수 후 공식 `DOCKER_TMPDIR`를 `/data/docker-export-tmp`로 지정했다. data-root와
containerd root는 이동하지 않는다. 루트15GiB 보호선도 유지한다.

적용은 `/run/systemd/system/docker.service.d/90-contextra-export-temp.conf`이며 현 부팅에만
유효하다. `/data` mount 의존성과 mountpoint/디렉터리 확인으로 미마운트 기동을 차단한다.
Docker 재시작에는 공용 서비스 중단 승인이 필요하다. CLI의 TMPDIR 변경만으로 대신하지 않는다.
완료 후 추가 중단을 피하기 위해 drop-in과 빈 임시 디렉터리는 유지하며 재부팅 시 원래 설정으로
돌아간다. 실행 중 임시파일 삭제·심볼릭 링크 우회·prune는 하지 않는다.

다음 export 전에 actual daemon 환경과 mount를 다시 확인한다. 이번 유지보수 승인은 이후의
재시작·강제 종료까지 포괄하지 않는다. 특히 정상 Stop 실패의 최초 오류와 승인된 강제 회수는
분리해 기록한다. SSIMS 채널은 사용자가 수동 복구하고 컨테이너 running만으로 영상 수용을 주장하지 않는다.
[Docker의 공식 daemon 환경변수](https://docs.docker.com/reference/cli/dockerd/#environment-variables).

## 작업 순서

1. 공유 FULL archive와 별도 전달한 SHA256을 `deployctl bundle verify`로 대조한다.
2. 현장 관제 HTTPS 주소, Event 주소, 계정/serverId, CA 공개 파일/지문을 확인한다.
3. 현장 사용자가 sudo 가능한 터미널에서 NVIDIA Toolkit의 Docker 연결을 적용한다.
   드라이버/SDK 교체나 설치를 먼저 하지 않는다. 기존 서비스가 있으면 중단 승인이 먼저다.
4. FULL 이미지 load와 지정 GPU smoke 후, 현장 GPU에서 Medium만 변환한다.
5. 새 후보의 deserialize·batch1~4 shape/dtype/finite 확인 뒤 Medium 전용 활성 repository에 배치한다.
6. private 경로/secret/Redis ACL과 인증서를 준비하고 최종 Compose를 검증한다.
7. 명시적 install 승인 뒤 readiness를 확인한다. 그 다음 승인된 두 카메라로 실제 연동을 확인한다.

각 단계에서 실패하면 오류 코드와 원장을 보존한다. 이미 완료된 변환/build/발급을 먼저
확인하며 같은 명령을 무조건 반복하지 않는다. 실제 설치·GPU 변환·카메라·Web 시험은 이번에 하지 않았다.

## 모델

기본은 FP16 입력, FP16 최적화, FP32 출력, min/opt/max batch1/4/4,
instance8, preferred4, queue5000us다. 이 값은 대상 PC 성능 수용 결과가 아니다.
ONNX의 알려진 출력 축은 검사하고, Pose의 추론되지 않은 symbolic 축은 기록한 뒤
실제 TensorRT engine/실행 검증에서 정확한 크기를 필수 확인한다. 품질 평가는 하지 않는다.

운영 image는 Python TensorRT/http-client extra를 포함하지 않는다. 별도 tooling image는
기존 ONNX 라이브러리와 같은 TensorRT C++ SDK로 계약 검사기를 컴파일하고, 기존 gRPC client를
재사용한다. 새 SDK 설치/교체나 패키지 다운로드는 없다. C++ 검사기의 대상 GPU deserialize는 미실행이다.
GPU별 engine 이식성을 가정하지 않으며 A6000 plan을 현장 실행용으로 배포하지 않는다.

```bash
# 아래 변수는 검증 완료한 실제 경로/immutable image ID로 지정한다.
./deployctl model build medium --onnx "$ONNX" --output "$NEW_CANDIDATE" --image "$BUILDER_ID"
# 계획 확인 후 같은 명령에 sudo 및 --apply를 추가한다.
./deployctl model verify "$NEW_CANDIDATE" --image "$BUILDER_ID"
./deployctl model install "$NEW_CANDIDATE" --destination "$MEDIUM_ONLY_REPOSITORY"
```

`required_models`와 활성 repository 디렉터리가 정확히 같아야 한다. 전체 repository를 read-only
mount하고 하위 모델 override mount는 금지한다. Triton repository index도 같은 모델만 READY인지
확인한다. Pose/Fire 원본·후속 후보는 활성 repository 밖에 두고 필요할 때만 별도 변환한다.

## 인증과 설정

- Event endpoint와 Manager HTTPS 인증 origin은 별도 입력이다. 현재 Sidecar는 동일 host만 허용한다.
- 공개 CA 지문 대조 → 기존 `secure_bridge_provision.py install-ca` →
  `secure_bridge_tls.py prepare` → `secure_bridge_enroll.py` → provision check → Gateway/Sidecar 순서다.
- enroll은 host 경로가 담긴 private 환경을 사용한다. 컨테이너의 `/run/bridge` 경로를 host에서
  그대로 사용하지 않는다. 기존 provision의 env 파서를 사용하고 shell로 임의 값을 평가하지 않는다.
- 유효한 인증서/키/SAN/CA와 세션을 재사용한다. 불명확한 ENROLL_INTENT를 지워 재발급하지 않는다.
- secret/세션/TLS 디렉터리와 파일은 실제 UID10001 접근 가능 여부를 확인한다. 공개 파일 이외에
  world-readable 권한을 주거나 test 서버 secret을 복제하지 않는다.
- lan_public은 `AI_ARTIFACT_LAN_CIDR`로 현장 private IPv4 subnet을 명시한다.
  RFC1918 밖/전체망/잘못된 CIDR은 거부한다. 기존 test 기본 subnet은 그대로 유지된다.
- Artifact 운영 기본값은 On/HTTP On이다. 사용자의 별도 Off 요청 없이 시험 종료만으로 끄지 않는다.
- 실제 미설정값을 대신한 fixture Compose PASS는 문법/재해석 검증일 뿐 설치 가능 판정이 아니다.

## 실패 후 재개

컨테이너에는 배포 transaction label을 기록하고 APPLY 전에 의도한 image ID를 원장에 저장한다.
최초 설치 실패 후에는 승인된 정상 Stop/reap·정지 확인을 먼저 한다. `recover`는 실제 label/image를
검증한 자기 자원만 REVIEWED로 표시하고, 컨테이너 ID가 다시 바뀌면 재개를 거부한다.
새 release ID로 재개하며 실패 폴더/원장은 보존한다. 자동 삭제·rollback은 하지 않는다.

```bash
./deployctl --site "$SITE" recover
# 출력한 inflight SHA와 실제 자원을 확인한 뒤에만:
sudo ./deployctl --site "$SITE" recover --expected "$INFLIGHT_SHA" --apply
./deployctl --site "$SITE" collect-support --output "$NEW_SUPPORT_ARCHIVE"
```

stderr 경고와 stdout JSON은 분리한다. 지원 자료에는 단계/오류 코드/고정 원인 분류/해시만
기록하며 임의 stderr·환경변수·Compose·token 원문은 포함하지 않는다.
Compose config JSON은 이미 처리된 `$` 표현을 다시 이스케이프하지 않고 실제 두 번째 config로 검증한다.

## 미커밋 소스와 배포물

기본 bundle은 정확한 commit과 worktree 일치를 요구한다. 명시적 `snapshot.files` 파일별 SHA256을
제공하면 `EXACT_WORKTREE`로 준비할 수 있다. 이 경우 `source_sha`는 기준 commit이고 최종 소스는
별도 snapshot digest다. 후보 SHA·파일 hash를 남기고 커밋된 release라고 표현하지 않는다.
같은 파일 허용 목록과 변경 감지/secret 제외가 적용되며 자동 commit은 하지 않는다.

첫 현장 수용 전까지 APP patch/rollback·장시간 성능·다중 모델·16채널 시험은 보류한다.
