<!-- task=01_setup_cli_core plan=2 tag=SETUPCORE-FIX2 -->

# Host Setup Core Follow-up Plan 2

## 이 파일을 읽는 구현 에이전트에게

직전 리뷰 `code_review_cloud_G07_1.log`의 FAIL 후속 작업이다. 범위는 `packages/hostsetup`의 data dir 권한 정합성과 recursive chown 안전장치 보강으로 제한한다. 구현 마지막에는 `CODE_REVIEW-cloud-G07.md`의 구현 에이전트 소유 섹션을 실제 변경 내용과 검증 출력으로 채운다.

## 배경

기존 follow-up은 leaf data dir과 config 파일을 `chown`하지만, 기본 경로 `/var/lib/iop/edge`, `/var/lib/iop/node`의 부모 `/var/lib/iop`가 fresh host에서 root:root `0750`으로 생성될 수 있다. 그러면 systemd의 `User=iop` 프로세스가 leaf data dir까지 traverse하지 못한다. 또한 `chown -R`가 caller supplied `DataDir`에 그대로 적용되어 상위 시스템 경로를 잘못 넘겼을 때 blast radius가 크다.

## 구현 체크리스트

- [x] [SETUPCORE-FIX2-1] 기본 nested data dir의 부모 경로까지 서비스 사용자가 traverse 가능하도록 권한/소유권 처리를 보강한다.
- [x] [SETUPCORE-FIX2-2] recursive chown 대상 data dir에 안전장치를 추가한다.
- [x] [SETUPCORE-FIX2-3] hostsetup 단위 테스트로 nested data dir와 unsafe data dir rejection을 검증한다.
- [x] 중간 검증과 최종 검증 명령을 실행하고 실제 출력을 기록한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

## 수정 범위

- `packages/hostsetup/setup.go`
- `packages/hostsetup/setup_test.go`

## 요구 사항

- `EdgeSpec()`/`NodeSpec()` 기본 data dir와 같은 `/var/lib/iop/<app>` 형태에서 `/var/lib/iop` 부모 경로를 서비스 사용자가 traverse할 수 있어야 한다.
- `DataDir`가 `/`, `/var`, `/var/lib`, `/etc`처럼 앱 전용 data dir로 보기 어려운 경로이면 recursive ownership 변경 전에 실패해야 한다.
- 기존 config no-overwrite 동작과 dry-run no-write/no-command 동작은 유지한다.
- 공통 패키지는 `apps/*/internal`을 import하지 않는다.

## 검증

```bash
gofmt -w packages/hostsetup
go test -count=1 ./packages/hostsetup
go test -count=1 ./packages/config ./packages/hostsetup
```
