<!-- task=m-jenkins-credential/02+01_crumb_token_store plan=3 tag=REVIEW_REVIEW_REVIEW_AUTH_TOKEN -->

# Plan - REVIEW_REVIEW_REVIEW_AUTH_TOKEN

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

이 plan은 직전 리뷰의 Required 이슈 1건만 해결한다. `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채우는 것이 구현의 마지막 단계다. 검증 명령을 실행하고 실제 stdout/stderr를 기록한 뒤 active 파일을 그대로 두고 리뷰를 요청한다. 사용자만 결정할 수 있는 Jenkins endpoint, credential, 조직 정책 blocker가 생기면 review stub의 `사용자 리뷰 요청`에 근거를 기록하고 멈춘다. 구현 중 사용자에게 직접 질문하거나 archive/log/complete.log를 직접 만들지 않는다.

## 배경

직전 구현은 WebView token 성공 경로의 double-pop을 제거하고 `JenkinsWebLoginResult.apiToken` 반환 경로로 통일했다. 하지만 `JenkinsWebLoginPage`에는 여전히 `onTokenIssued` 생성자 파라미터와 `JenkinsTokenIssuedCallback` typedef가 남아 있고, 주석은 token 발급 성공 시 callback이 호출된다고 설명한다. 현재 `_issueToken`은 이 callback을 호출하지 않으므로 public API contract와 구현 기록이 어긋난다.

## 사용자 리뷰 요청 흐름

구현 중 blocker는 active review stub의 `사용자 리뷰 요청` 섹션에 기록한다. 후속 에이전트가 재실행으로 해소할 수 있는 검증 공백은 사용자 리뷰 요청이 아니며, code-review가 최종 stop 여부를 판단한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/usable-mvp/milestones/jenkins-credential.md`
- Task ids:
  - `crumb-token`: WebView same-origin 요청으로 crumb를 받고 사용자별 API token을 자동 발급한다.
  - `keychain-store`: 자동 발급한 username/API token을 `TokenStore`를 통해 macOS Keychain에 저장하고 삭제할 수 있다.
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `agent-ops/skills/common/code-review/SKILL.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`
- `agent-task/m-jenkins-credential/02+01_crumb_token_store/plan_cloud_G06_2.log`
- `agent-task/m-jenkins-credential/02+01_crumb_token_store/code_review_cloud_G06_2.log`
- `lib/src/features/settings/jenkins_web_login_page.dart`
- `lib/src/features/settings/settings_page.dart`
- `test/jenkins_web_auth_bridge_test.dart`
- `test/settings_page_test.dart`

### 리뷰 검증

- `flutter analyze`: 통과.
- `flutter test test/jenkins_web_auth_bridge_test.dart test/settings_page_test.dart`: 통과.
- `flutter test test/app_auth_test.dart test/widget_test.dart`: 통과.
- `flutter test`: 통과.
- `git diff --check`: 통과.
- 현재 Linux/container checkout의 Flutter 검증은 preflight다. 완료 evidence는 remote Mac runner 기준으로 다시 기록한다.

### 범위 결정 근거

- 포함: unused `JenkinsTokenIssuedCallback`/`JenkinsWebLoginPage.onTokenIssued` 제거, 관련 stale comment/test comment 정리, stale reference 검증.
- 제외: token bridge JS 동작 변경, `SettingsPage` token saving 흐름 변경, 실제 Jenkins sandbox 수동 smoke.

### 빌드 등급

- `cloud-G06`: follow-up 자체는 작지만, 동일 Jenkins auth/token task의 API contract 정리이며 기존 cloud route를 유지한다.

## 구현 체크리스트

- [ ] `JenkinsWebLoginPage`의 unused `JenkinsTokenIssuedCallback` typedef, `onTokenIssued` constructor parameter, field, stale comment를 제거하고 `JenkinsWebLoginResult.apiToken` 단일 결과 계약으로 정리한다.
- [ ] 테스트/주석에서 `onTokenIssued` 참조를 제거하거나 현재 단일 결과 계약을 정확히 설명하도록 고친다.
- [ ] 최종 검증 명령을 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## 의존 관계 및 구현 순서

- 이 subtask는 directory name `02+01_crumb_token_store` 기준으로 `01_web_login_entry` 완료에 의존한다.
- predecessor evidence는 이전 loop에서 확인됐다.

### [REVIEW_REVIEW_REVIEW_AUTH_TOKEN-1] Remove Stale Token Callback API

#### 문제

[jenkins_web_login_page.dart](/config/workspace/appsok/lib/src/features/settings/jenkins_web_login_page.dart:180)의 `JenkinsTokenIssuedCallback`과 [jenkins_web_login_page.dart](/config/workspace/appsok/lib/src/features/settings/jenkins_web_login_page.dart:187)의 `onTokenIssued` parameter는 현재 호출되지 않는다. 그런데 [jenkins_web_login_page.dart](/config/workspace/appsok/lib/src/features/settings/jenkins_web_login_page.dart:192)의 주석은 token 발급 성공 시 callback이 호출된다고 설명한다. 실제 구현은 [jenkins_web_login_page.dart](/config/workspace/appsok/lib/src/features/settings/jenkins_web_login_page.dart:289)에서 `JenkinsWebLoginResult(apiToken: ...)`를 pop하는 단일 결과 계약이므로, public API 표면과 설명을 맞춰야 한다.

Before:

```dart
typedef JenkinsTokenIssuedCallback =
    void Function(String username, String? displayName, String apiToken);

const JenkinsWebLoginPage({
  required this.baseUrl,
  this.onTokenIssued,
});
```

#### 해결 방법

- `JenkinsTokenIssuedCallback` typedef를 제거한다.
- `JenkinsWebLoginPage` 생성자에서 `onTokenIssued` optional parameter를 제거한다.
- `final JenkinsTokenIssuedCallback? onTokenIssued;` field와 stale comment를 제거한다.
- `test/jenkins_web_auth_bridge_test.dart`의 "without a separate onTokenIssued callback" 주석은 현재 계약을 정확히 설명하도록 유지하거나 더 명확하게 고친다.
- `rg --line-number "onTokenIssued|JenkinsTokenIssuedCallback" lib test`가 결과를 내지 않도록 정리한다.

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

- [ ] `lib/src/features/settings/jenkins_web_login_page.dart`: unused callback API 제거.
- [ ] `test/jenkins_web_auth_bridge_test.dart`: stale callback comment/reference 제거.

#### 테스트 작성

- 새 동작 테스트는 필요 없다. 기존 `JenkinsWebLoginResult.apiToken` contract test와 stale reference grep으로 충분하다.

#### 중간 검증

```bash
rg --line-number "onTokenIssued|JenkinsTokenIssuedCallback" lib test
flutter test test/jenkins_web_auth_bridge_test.dart test/settings_page_test.dart
```

예상: `rg` 결과 없음, Web Login result/callback contract 관련 테스트 통과.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `lib/src/features/settings/jenkins_web_login_page.dart` | REVIEW_REVIEW_REVIEW_AUTH_TOKEN-1 |
| `test/jenkins_web_auth_bridge_test.dart` | REVIEW_REVIEW_REVIEW_AUTH_TOKEN-1 |

## 최종 검증

```bash
zsh -lc 'cd "$HOME/docker/services/code-server/data/volume/workspace/appsok" && flutter analyze'
zsh -lc 'cd "$HOME/docker/services/code-server/data/volume/workspace/appsok" && flutter test'
```

예상: analyzer issue 없음, 모든 테스트 통과. 실제 Jenkins sandbox endpoint가 없으면 수동 smoke 생략 사유를 review stub에 기록한다.

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