<!-- task=m-mattermost-messaging-android-smoke/02+01_runtime_notification_smoke plan=0 tag=SMOKE_RUNTIME -->

# Plan - SMOKE_RUNTIME

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

`CODE_REVIEW-cloud-G08.md`의 구현 에이전트 소유 섹션 작성까지가 구현의 일부다. 실제 device/emulator와 Mattermost trigger 결과를 secret 없이 기록하고, active 파일을 유지한 채 리뷰 준비를 보고한다. 최종 archive, `complete.log`, PASS/WARN/FAIL 판정은 code-review skill 전용이다.

## 배경

이 작업은 `01_remote_build`가 Android debug APK build를 통과한 뒤에만 시작한다. 목적은 사용자 테스트가 아니라 Android runtime smoke다: 앱 boot, Firebase initialization, Mattermost auth/token handoff, notification callback, Android 시스템 알림 도착 여부를 확인한다.

## 분석 결과

### 읽은 파일

- `agent-ops/roadmap/current.md`
- `agent-ops/roadmap/phase/external-integration/PHASE.md`
- `agent-ops/roadmap/phase/external-integration/milestones/mattermost-messaging-android-smoke.md`
- `docs/test-environments.md`
- `apps/client/pubspec.yaml`
- `apps/client/README.md`
- `apps/client/push-notification-todo.md`
- `apps/client/lib/src/app/bootstrap.dart`
- `apps/client/lib/src/app/nomadcode_client_app.dart`
- `apps/client/lib/src/integrations/mattermost/mattermost_push_client.dart`
- `apps/client/lib/src/integrations/mattermost/mattermost_push_plugin_client.dart`
- `apps/client/lib/src/integrations/mattermost/mattermost_push_host_integration.dart`
- `apps/client/lib/src/integrations/mattermost/mattermost_auth_service.dart`
- `apps/client/test/integrations/mattermost_push_host_integration_test.dart`
- `apps/client/android/app/build.gradle.kts`
- `apps/client/android/app/src/main/AndroidManifest.xml`
- `../nexo/packages/messaging_flutter/pubspec.yaml`
- `../nexo/packages/messaging_flutter/README.md`
- `../nexo/packages/messaging_flutter/lib/nexo_messaging.dart`
- `../nexo/packages/messaging_flutter/lib/src/nexo_messaging_plugin.dart`
- `../nexo/packages/messaging_flutter/lib/src/notification_opened_event.dart`
- `../nexo/packages/messaging_flutter/lib/src/push_notification_type.dart`
- `../nexo/packages/messaging_flutter/android/src/main/AndroidManifest.xml`
- `../nexo/packages/messaging_flutter/android/src/main/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPlugin.kt`
- `../nexo/packages/messaging_flutter/android/src/main/kotlin/com/tokilabs/nexo/messaging/NexoFirebaseMessagingService.kt`
- `../nexo/packages/messaging_flutter/test/nexo_messaging_test.dart`

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

- Existing host tests cover only fake push client behavior; they do not boot Firebase, request Android notification permission, register FCM, or display a system notification.
- `../nexo/packages/messaging_flutter/test/nexo_messaging_test.dart` covers Dart event parsing and callbacks, not true Firebase FCM delivery.
- This plan intentionally uses device/emulator smoke and may still leave full end-user UAT outside scope.

### 심볼 참조

- Naming refactor is complete in the plugin package. Runtime work should exercise current host `MattermostPushClient` / `MattermostPushPluginClient` boundary names together with plugin package `nexo_messaging`, singleton `NexoMessagingPlugin`, and Android service `NexoFirebaseMessagingService`.
- Do not look for pre-refactor native service names in runtime logs unless they appear as a regression.

### 분할 판단

Split decision policy was evaluated before writing plan files. Shared task group: `m-mattermost-messaging-android-smoke`.

- `01_remote_build`: predecessor, must complete before this task.
- `02+01_runtime_notification_smoke`: depends on `01_remote_build` because runtime smoke should start from a known buildable APK.

### 범위 결정 근거

This task may make only narrow app/plugin integration fixes needed to boot or receive a notification. It must not add product UX, commit credentials, implement server-side Mattermost functionality, or broaden into iOS/macOS. If the device, Firebase, or Mattermost trigger environment is unavailable, record a blocker instead of faking evidence.

### 빌드 등급

`cloud-G08`: runtime smoke depends on interactive device/emulator state, Firebase/Mattermost auth flow, external API trigger, Android logs, and notification observation.

## 의존 관계 및 구현 순서

`02+01_runtime_notification_smoke` depends on sibling `01_remote_build`. Before starting, verify the predecessor has a `complete.log` either in the active task path or in `agent-task/archive/**/m-mattermost-messaging-android-smoke/01_remote_build/`.

## 구현 체크리스트

- [ ] `01_remote_build` PASS completion evidence exists before runtime work starts.
- [ ] Remote runner에서 Android device 또는 emulator를 확인하고 선택한 device id를 기록한다.
- [ ] 앱을 device/emulator에 설치 또는 실행하고, app boot/Firebase initialization/Mattermost auth handoff 로그를 확인한다.
- [ ] Mattermost 메시지 또는 push trigger를 실행하고 Android notification/log/callback evidence를 secret 없이 기록한다.
- [ ] 성공 또는 blocker 결과를 `CODE_REVIEW-cloud-G08.md`에 실제 stdout/stderr와 관찰 메모로 남긴다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [SMOKE_RUNTIME-1] Dependency And Device Preflight

문제: `agent-ops/roadmap/phase/external-integration/milestones/mattermost-messaging-android-smoke.md:37` requires a device or emulator runtime smoke, and `docs/test-environments.md:50`-`60` says a device/emulator is required for notification/device behavior.

해결 방법: confirm predecessor completion, then discover an Android device/emulator on the remote runner. If none exists, stop with an environment blocker.

수정 파일 및 체크리스트:

- [ ] 소스 수정 없음.
- [ ] `CODE_REVIEW-cloud-G08.md`에 predecessor evidence path와 selected device id를 기록한다.

테스트 작성: 새 테스트 없음. This is environment preflight.

중간 검증:

```bash
test -f agent-task/m-mattermost-messaging-android-smoke/01_remote_build/complete.log || find agent-task/archive -path '*/m-mattermost-messaging-android-smoke/01_remote_build/complete.log' -print -quit | grep -q .
```

Expected: predecessor PASS evidence exists.

```bash
ssh toki@toki-labs.com 'set -euo pipefail; cd /config/workspace/nomadcode/apps/client; flutter devices'
```

Expected: at least one Android device or emulator is listed.

### [SMOKE_RUNTIME-2] App Boot And Firebase/Mattermost Handoff

문제: `apps/client/lib/src/app/bootstrap.dart:37`-`38` initializes Firebase and the Mattermost host integration, while `apps/client/lib/src/integrations/mattermost/mattermost_auth_service.dart:22`-`53` performs credential-based login and device token registration. Unit tests do not prove this path boots on Android.

해결 방법: run the app on the selected Android target. Capture logs showing boot, Firebase initialization did not crash, and Mattermost auth/token handoff either succeeded or skipped due to missing ignored credentials. If credentials are missing, runtime notification arrival cannot PASS and must be recorded as blocker.

수정 파일 및 체크리스트:

- [ ] `apps/client/pubspec.yaml` only if asset/runtime config needs a narrow correction.
- [ ] `apps/client/lib/src/integrations/mattermost/*.dart` only if runtime exposes a compile/boot mismatch.
- [ ] `CODE_REVIEW-cloud-G08.md` records actual command output and observation.

테스트 작성: 새 unit test는 작성하지 않는다. This path depends on Firebase/device runtime.

중간 검증:

```bash
ssh toki@toki-labs.com 'set -euo pipefail; cd /config/workspace/nomadcode/apps/client; DEVICE_ID="$(flutter devices | awk -F "•" "/android|Android/ {gsub(/^ +| +$/, \"\", \$2); print \$2; exit}")"; test -n "$DEVICE_ID"; timeout 180s flutter run -d "$DEVICE_ID" --verbose'
```

Expected: app starts far enough to show Flutter boot; timeout exit is acceptable only if logs show the app booted before the harness cutoff.

### [SMOKE_RUNTIME-3] Notification Arrival Smoke

문제: `agent-ops/roadmap/phase/external-integration/milestones/mattermost-messaging-android-smoke.md:38` requires a Mattermost message or push trigger to produce an Android system notification. This cannot be proven by local tests.

해결 방법: with the app installed and credentials available on the remote runner, background the app, trigger a Mattermost post through configured environment variables, and watch Android logs/notification behavior. Required remote env vars are `MATTERMOST_BASE_URL`, `MATTERMOST_TOKEN`, and `MATTERMOST_TEST_CHANNEL_ID`; do not print their values.

수정 파일 및 체크리스트:

- [ ] 소스 수정 없음 unless a narrow runtime regression is proven.
- [ ] `CODE_REVIEW-cloud-G08.md` records trigger command output with secrets redacted or absent.
- [ ] Record whether system notification appeared and whether callback/log path was observed.

테스트 작성: 새 unit test는 작성하지 않는다. Manual/device smoke is the acceptance signal.

중간 검증:

```bash
ssh toki@toki-labs.com 'set -euo pipefail; cd /config/workspace/nomadcode/apps/client; DEVICE_ID="$(flutter devices | awk -F "•" "/android|Android/ {gsub(/^ +| +$/, \"\", \$2); print \$2; exit}")"; test -n "$DEVICE_ID"; adb -s "$DEVICE_ID" logcat -c; adb -s "$DEVICE_ID" shell input keyevent 3; test -n "${MATTERMOST_BASE_URL:-}"; test -n "${MATTERMOST_TOKEN:-}"; test -n "${MATTERMOST_TEST_CHANNEL_ID:-}"; curl -sS -f -H "Authorization: Bearer $MATTERMOST_TOKEN" -H "Content-Type: application/json" -d "{\"channel_id\":\"$MATTERMOST_TEST_CHANNEL_ID\",\"message\":\"NomadCode Android notification smoke $(date -u +%Y-%m-%dT%H:%M:%SZ)\"}" "$MATTERMOST_BASE_URL/api/v4/posts" >/tmp/nomadcode-mattermost-smoke-post.json; timeout 120s adb -s "$DEVICE_ID" logcat -v time | grep -E "PushNotification|MattermostHost|NexoFirebaseMessagingService|FirebaseMessaging"'
```

Expected: curl succeeds, logs show push/notification or callback activity, and the implementer records whether an Android system notification appeared. If required env vars are absent, report an environment blocker.

### [SMOKE_RUNTIME-4] Evidence Note

문제: `agent-ops/roadmap/phase/external-integration/milestones/mattermost-messaging-android-smoke.md:39` requires evidence and limitations to be available for completion review.

해결 방법: summarize build predecessor, runtime boot, notification trigger, observed result, and any blocker in `CODE_REVIEW-cloud-G08.md`. Do not update roadmap completion directly; PASS metadata will be consumed by runtime/update-roadmap.

수정 파일 및 체크리스트:

- [ ] `CODE_REVIEW-cloud-G08.md` contains evidence, limitations, and no secrets.

테스트 작성: 새 테스트 없음.

중간 검증:

```bash
rg --sort path -n "Authorization: Bearer [A-Za-z0-9._-]{12,}|\"token\": \"[A-Za-z0-9._:-]{12,}|\"device_id\": \"[A-Za-z0-9._:-]{12,}|\"signingKey\": \"[A-Za-z0-9._:-]{12,}" agent-task/m-mattermost-messaging-android-smoke/02+01_runtime_notification_smoke/CODE_REVIEW-cloud-G08.md
```

Expected: no matches. If this command prints a match, redact before review.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `apps/client/pubspec.yaml` | SMOKE_RUNTIME-2, only if needed |
| `apps/client/lib/src/integrations/mattermost/*.dart` | SMOKE_RUNTIME-2, only if needed |
| `agent-task/m-mattermost-messaging-android-smoke/02+01_runtime_notification_smoke/CODE_REVIEW-cloud-G08.md` | SMOKE_RUNTIME-1..4 |

## 최종 검증

```bash
test -f agent-task/m-mattermost-messaging-android-smoke/01_remote_build/complete.log || find agent-task/archive -path '*/m-mattermost-messaging-android-smoke/01_remote_build/complete.log' -print -quit | grep -q .
```

Expected: predecessor PASS evidence exists.

```bash
ssh toki@toki-labs.com 'set -euo pipefail; cd /config/workspace/nomadcode/apps/client; flutter devices'
```

Expected: Android device/emulator is available.

```bash
rg --sort path -n "Authorization: Bearer [A-Za-z0-9._-]{12,}|\"token\": \"[A-Za-z0-9._:-]{12,}|\"device_id\": \"[A-Za-z0-9._:-]{12,}|\"signingKey\": \"[A-Za-z0-9._:-]{12,}" agent-task/m-mattermost-messaging-android-smoke/02+01_runtime_notification_smoke/CODE_REVIEW-cloud-G08.md
```

Expected: no matches.

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