<!-- task=m-jenkins-credential/03_reauth_status_model plan=0 tag=REAUTH_STATUS -->

# Plan - REAUTH_STATUS

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

이 파일은 구현 루프의 입력이다. 구현 후 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 변경 내용과 검증 출력으로 채우고, active 파일을 그대로 둔 채 리뷰 준비를 보고한다. 구현 중 사용자만 결정할 수 있는 범위 변경, 사용자 소유 외부 환경, secret, 서비스 준비가 막히면 리뷰 stub의 `사용자 리뷰 요청`에 근거를 기록하고 멈춘다. 구현 에이전트는 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 재실행으로 채울 수 있는 검증 증거 공백은 사용자 리뷰 요청이 아니라 후속 검증 이슈다. archive, `complete.log`, task-directory 이동은 code-review 전용이다.

## 배경

현 마일스톤의 `session-restore` 에픽에서 남은 큰 작업은 `reauth`다. 현재 `JenkinsArtifactSession.restore()`는 성공/실패만 반환해 credential 없음, 401/403 재로그인 필요, 네트워크 실패, 서버 실패를 구분할 수 없다. UI가 안전하게 안내하려면 먼저 service layer에서 원인 보존형 restore 결과가 필요하다.

## 사용자 리뷰 요청 흐름

구현 중 사용자 결정이나 사용자 소유 환경 때문에 멈춰야 하면 active review stub의 `사용자 리뷰 요청` 섹션을 채운다. 직접 사용자에게 질문하지 않으며, code-review가 그 요청을 검증하고 필요 시 `USER_REVIEW.md`를 작성한다.

## 분석 결과

### 읽은 파일

- `agent-roadmap/current.md`
- `agent-roadmap/phase/usable-mvp/PHASE.md`
- `agent-roadmap/phase/usable-mvp/milestones/jenkins-credential.md`
- `agent-ops/rules/project/domain/artifact-flow/rules.md`
- `agent-ops/rules/project/domain/app-shell/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/artifact-flow-smoke.md`
- `agent-test/local/app-shell-smoke.md`
- `lib/src/services/jenkins_artifact_session.dart`
- `lib/src/services/jenkins_client.dart`
- `lib/src/services/token_store.dart`
- `test/jenkins_artifact_session_test.dart`
- `test/jenkins_client_test.dart`
- `test/token_store_test.dart`

### 테스트 환경 규칙

- test_env: `local`
- `agent-test/local/rules.md`를 읽었다. 완료 evidence는 standard remote Mac runner 기준이며 현재 checkout Flutter 실행은 preflight로만 본다.
- matched profiles:
  - `agent-test/local/artifact-flow-smoke.md`: `flutter analyze`, `flutter test`를 remote runner에서 실행해야 한다.
  - `agent-test/local/app-shell-smoke.md`: 후속 UI task가 app-shell을 만지므로 split 전체 검증 기준으로 읽었다.
- 이 foundation task의 focused 검증은 `flutter test test/jenkins_artifact_session_test.dart test/jenkins_client_test.dart`이고, 최종 검증은 remote runner의 analyzer와 focused tests다.

### 테스트 커버리지 공백

- `restore()` 성공/credential 없음 bool 동작은 기존 `test/jenkins_artifact_session_test.dart`가 일부 커버한다.
- 401/403이 credential을 삭제한다는 직접 service test가 부족하다.
- 네트워크 실패(`IOException`)와 non-auth `JenkinsClientException`이 credential을 보존하면서 서로 다른 원인으로 반환되는 테스트가 없다.

### 심볼 참조

- 변경 예정: `JenkinsArtifactSession.restore()` 호출 계약. call site는 `lib/src/app.dart`, `test/jenkins_artifact_session_test.dart`, `test/app_auth_test.dart`, `test/widget_test.dart`의 fake session 구현이다.
- 제거 예정 symbol 없음. 가능하면 `restore()` bool wrapper는 유지해 기존 call site 파손을 줄이고, 새 상세 API를 추가한다.

### 분할 판단

- split decision policy를 먼저 평가했다.
- 공유 task group: `m-jenkins-credential`
- 계획:
  - `03_reauth_status_model`: restore 원인 보존 모델과 service tests. 독립 선행 task다.
  - `04+03_reauth_ui`: `03_reauth_status_model` 완료 후 앱/빌드 UI가 상세 상태를 사용한다.
- API foundation과 UI rollout이 분리되고 테스트 전략도 service test와 widget/app test로 다르므로 split gate에 해당한다.
- 이 task는 predecessor가 없다.

### 범위 결정 근거

- 이 task는 service-layer restore 결과 모델만 다룬다.
- `AppSokApp`, `AppSokShell`, `BuildsPage`, `SettingsPage`의 사용자 안내와 retry/re-login UX는 `04+03_reauth_ui`에서 처리한다.
- `logout-clear`는 작은 작업으로 직접 구현되어 이 계획 범위에서 제외한다.

### 빌드 등급

- `local-G06`: auth/storage 결과 모델 변경이지만 변경 지점과 테스트가 service layer에 한정되어 있고 deterministic focused tests로 검증 가능하다.

## 구현 체크리스트

- [ ] `JenkinsArtifactSession`에 credential 없음, restored, reauth required, network failure, server failure를 구분하는 상세 restore 결과 API를 추가하고 기존 bool `restore()` 호환성을 유지한다.
- [ ] `test/jenkins_artifact_session_test.dart`에 401/403 clear, network 보존, server failure 보존, bool wrapper 호환 테스트를 추가한다.
- [ ] `flutter test test/jenkins_artifact_session_test.dart test/jenkins_client_test.dart`로 중간 검증한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REAUTH_STATUS-1] Restore Result Model

#### 문제

[jenkins_artifact_session.dart](/config/workspace/appsok/lib/src/services/jenkins_artifact_session.dart:22)의 `restore()`는 모든 실패를 `false`로 압축한다.

Before:

```dart
// lib/src/services/jenkins_artifact_session.dart:22
Future<bool> restore() async {
  final session = await store.readSession();
  if (session == null) {
    _session = null;
    return false;
  }
  ...
}
```

이 상태로는 후속 UI가 저장 credential 없음, 401/403 재로그인 필요, 네트워크 실패, Jenkins 서버 오류를 구분할 수 없다.

#### 해결 방법

- `JenkinsSessionRestoreKind` enum과 `JenkinsSessionRestoreResult` value object를 `jenkins_artifact_session.dart`에 추가한다.
- 새 `restoreDetailed()`가 다음 상태를 반환한다.
  - `missing`: 저장된 session 없음 또는 불완전한 저장값.
  - `restored`: `/whoAmI` 검증 성공.
  - `reauthRequired`: `JenkinsClientException.statusCode` 401 또는 403. 이 경우 `store.clearSession()`을 유지한다.
  - `networkFailure`: `IOException`. credential은 삭제하지 않는다.
  - `serverFailure`: 401/403이 아닌 `JenkinsClientException`. credential은 삭제하지 않는다.
- 기존 `restore()`는 `return (await restoreDetailed()).isRestored;` 형태의 bool wrapper로 유지한다.

#### 수정 파일 및 체크리스트

- [ ] `lib/src/services/jenkins_artifact_session.dart`: enum/result class와 `restoreDetailed()` 추가, 기존 `restore()` wrapper화.
- [ ] `test/jenkins_artifact_session_test.dart`: 상세 상태와 저장소 side effect 테스트 추가.

#### 테스트 작성

- `restoreDetailed returns missing when config is missing`
- `restoreDetailed returns restored after current user validation`
- `restoreDetailed returns reauthRequired and clears session on 401/403`
- `restoreDetailed returns networkFailure and keeps session on IOException`
- `restoreDetailed returns serverFailure and keeps session on non-auth JenkinsClientException`
- `restore bool wrapper remains true only for restored`

#### 중간 검증

```bash
flutter test test/jenkins_artifact_session_test.dart test/jenkins_client_test.dart
```

예상: service focused tests 통과.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `lib/src/services/jenkins_artifact_session.dart` | REAUTH_STATUS-1 |
| `test/jenkins_artifact_session_test.dart` | REAUTH_STATUS-1 |

## 최종 검증

```bash
git diff --check
flutter test test/jenkins_artifact_session_test.dart test/jenkins_client_test.dart
ssh -o BatchMode=yes -o ConnectTimeout=10 toki@toki-labs.com 'zsh -lc '\''cd "$HOME/docker/services/code-server/data/volume/workspace/appsok" && flutter analyze && flutter test test/jenkins_artifact_session_test.dart test/jenkins_client_test.dart'\'''
```

예상: 공백 오류 없음, focused tests 통과, remote analyzer issue 없음.

모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.
