diff --git a/agent-roadmap/current.md b/agent-roadmap/current.md index 7eeca2ea..e9a303a9 100644 --- a/agent-roadmap/current.md +++ b/agent-roadmap/current.md @@ -7,7 +7,7 @@ ## 활성 Milestone -- [계획] 클라이언트 검증 기준선 +- [진행중] 클라이언트 검증 기준선 - Phase: `agent-roadmap/phase/product-foundation/PHASE.md` - 경로: `agent-roadmap/phase/product-foundation/milestones/client-validation.md` diff --git a/agent-roadmap/phase/product-foundation/PHASE.md b/agent-roadmap/phase/product-foundation/PHASE.md index f6cd10b0..53c07c7d 100644 --- a/agent-roadmap/phase/product-foundation/PHASE.md +++ b/agent-roadmap/phase/product-foundation/PHASE.md @@ -24,7 +24,7 @@ nexo를 Mattermost 기반 서버/front/push-proxy 런타임과 nexo-owned Flutte - [완료] 이미지 기반 런타임 검증 - 경로: `agent-roadmap/archive/phase/product-foundation/milestones/runtime-image-validation.md` - 요약: nexo-owned Mattermost/push-proxy image build, 배포/수신 방식, 원격 Mac runtime 전환, 현 repo와 소비 프로젝트 smoke/e2e 검증 기준선을 만들고 잔여 Detox app-readiness 실패를 후속으로 분리했다. -- [계획] 클라이언트 검증 기준선 +- [진행중] 클라이언트 검증 기준선 - 경로: `agent-roadmap/phase/product-foundation/milestones/client-validation.md` - 요약: `apps/flutter-test`가 플러그인 소비 앱이자 테스트 호스트로 반복 검증을 제공하도록 고정한다. diff --git a/agent-roadmap/phase/product-foundation/milestones/client-validation.md b/agent-roadmap/phase/product-foundation/milestones/client-validation.md index 0f4f78b3..ab9dc0c1 100644 --- a/agent-roadmap/phase/product-foundation/milestones/client-validation.md +++ b/agent-roadmap/phase/product-foundation/milestones/client-validation.md @@ -12,7 +12,7 @@ ## 상태 -[계획] +[진행중] ## 승격 조건 @@ -37,10 +37,10 @@ `apps/flutter-test` 앱을 플러그인 통합 검증에 필요한 만큼만 유지한다. -- [ ] [thin-client] `apps/flutter-test`가 제품 UI가 아니라 plugin integration host 역할을 유지하도록 README와 테스트가 같은 기준을 따른다. +- [x] [thin-client] `apps/flutter-test`가 제품 UI가 아니라 plugin integration host 역할을 유지하도록 README와 테스트가 같은 기준을 따른다. - [ ] [integration-path] plugin method channel, event channel, opened-routing 통합 테스트 경로를 유지한다. 검증: `cd apps/flutter-test && flutter test integration_test`가 지원 환경에서 성공한다. - [ ] [native-test] Android native unit test 실행 절차를 유지한다. 검증: `cd apps/flutter-test/android && ./gradlew testDebugUnitTest`가 Android SDK 환경에서 성공한다. -- [ ] [sdk-boundary] Flutter SDK Android 구현은 Mattermost mobile code를 팔로잉하지 않고 server/push contract와 Android/FCM platform 변화만 추적한다는 기준을 문서화한다. +- [x] [sdk-boundary] Flutter SDK Android 구현은 Mattermost mobile code를 팔로잉하지 않고 server/push contract와 Android/FCM platform 변화만 추적한다는 기준을 문서화한다. ### Epic: [manual-smoke] 외부 인프라 smoke @@ -69,6 +69,8 @@ - 관련 경로: `apps/flutter-test/`, `packages/messaging_flutter/`, `packages/messaging_flutter/docs/android-test-environment.md` - 표준선(선택): client는 실제 소비 앱 모양의 검증 호스트이며 별도 `/example`이나 `/sandbox`를 두지 않는다. Flutter SDK는 nexo-owned embedded SDK로 유지한다 +- 진행 메모: `thin-client`는 `apps/flutter-test/README.md`와 `apps/flutter-test/test/widget_test.dart` 기준을 맞췄다. `sdk-boundary`는 `packages/messaging_flutter/README.md`의 SDK ownership/test strategy 기준을 보강했다. +- 활성 계획: `agent-task/m-client-validation/01_integration_path/`, `agent-task/m-client-validation/02_native_test/` - 선행 작업: client migration과 1차 테스트 - 후속 작업: 메시징 계약 표준화, 알림 파이프라인 고도화 - 확인 필요: 없음 diff --git a/agent-task/m-client-validation/02_native_test/CODE_REVIEW-cloud-G07.md b/agent-task/m-client-validation/02_native_test/CODE_REVIEW-cloud-G07.md new file mode 100644 index 00000000..8b4d8fa2 --- /dev/null +++ b/agent-task/m-client-validation/02_native_test/CODE_REVIEW-cloud-G07.md @@ -0,0 +1,139 @@ + + +# Code Review Reference - TEST + +> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.** +> The task is NOT complete until every implementation-owned section below is filled in. +> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving. +> Fill implementation-owned sections, then stop with active files in place and report ready for review. +> If implementation is blocked by a user-only decision, external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. +> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume. +> Follow the ownership table at the bottom of this file for which sections you own. + +## 개요 + +date=2026-05-29 +task=m-client-validation/02_native_test, plan=0, tag=TEST + +## 이 파일을 읽는 리뷰 에이전트에게 + +> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다. + +각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요. +리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다. + +1. 판정을 append한다. +2. `CODE_REVIEW-cloud-G07.md` → `code_review_cloud_G07_N.log`, `PLAN-cloud-G07.md` → `plan_cloud_G07_M.log`로 아카이브한다. +3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-client-validation/02_native_test/`로 이동한다. WARN/FAIL이면 user-review gate를 확인한 뒤 다음 active plan/review 파일 또는 `USER_REVIEW.md`를 작성한다. `USER_REVIEW.md`가 사용자 결정으로 완료/PASS 해소되면 code-review가 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log` 작성 후 archive 이동한다. +4. PASS이고 task group이 `m-`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다. +5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다. + +--- + +## 구현 항목별 완료 여부 + +| 항목 | 완료 여부 | +|------|---------| +| [TEST-1] Android Gradle native unit test execution | [ ] | + +## 구현 체크리스트 + +- [ ] Android SDK/Gradle preflight를 확인하고, 없으면 `사용자 리뷰 요청`에 실제 출력과 재개 조건을 기록한다. +- [ ] `cd apps/flutter-test/android && ./gradlew testDebugUnitTest`가 Android SDK 환경에서 성공하도록 확인한다. 실패가 제품 결함이면 이 계획의 파일 경계 안에서 최소 수정 후 같은 명령을 재실행한다. +- [ ] Native unit test coverage gaps are not expanded unless the command reveals a failing product behavior in the existing tests. +- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 코드리뷰 전용 체크리스트 + +> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다. +> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다. + +- [ ] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다. +- [ ] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다. +- [ ] active `CODE_REVIEW-*-G??.md`를 `code_review_cloud_G07_N.log`로 아카이브한다. +- [ ] active `PLAN-*-G??.md`를 `plan_cloud_G07_M.log`로 아카이브한다. +- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다. +- [ ] PASS이면 active task 디렉터리 `agent-task/m-client-validation/02_native_test/`를 `agent-task/archive/YYYY/MM/m-client-validation/02_native_test/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다. +- [ ] PASS이고 task group이 `m-`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다. +- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-client-validation/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다. +- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-cloud-G07.md`와 `CODE_REVIEW-cloud-G07.md`를 작성하고 `complete.log`를 작성하지 않는다. +- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다. +- [ ] USER_REVIEW가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다. + +## 계획 대비 변경 사항 + +_구현 에이전트가 계획과 다르게 구현한 부분을 이유와 함께 기록한다._ + +## 주요 설계 결정 + +_구현 에이전트가 주요 설계 결정 사항을 기록한다._ + +## 사용자 리뷰 요청 + +_기본값은 `없음`이다. 구현 중 사용자 결정, 외부 환경 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. code-review가 이 내용을 검증해 `USER_REVIEW.md`를 작성한다._ + +- 상태: 없음 +- 사유 유형: 없음 +- 결정 필요: 없음 +- 차단 근거: 없음 +- 실행한 검증/명령: 없음 +- 재개 조건: 없음 + +## 리뷰어를 위한 체크포인트 + +- Android SDK/Flutter SDK metadata 부재를 제품 실패로 고치지 않았는지 확인한다. +- `./gradlew testDebugUnitTest` output이 실제 Gradle 실행 결과인지 확인한다. +- native coverage expansion을 이 계획 범위 밖으로 키우지 않았는지 확인한다. + +## 검증 결과 + +_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._ + +필수 규칙: +- 검증 명령은 고정된 계약이다. 임의로 대체하지 않는다. +- 대체가 필요하면 `계획 대비 변경 사항`에 이유와 대체 명령을 기록한다. +- `검증 결과`에는 실제 stdout/stderr를 붙여 넣는다. +- 사용자 리뷰 요청으로 명령을 끝까지 실행하지 못했다면 `사용자 리뷰 요청`에 실행한 명령, 실제 출력, 미실행 명령의 사유를 기록한다. + +### TEST-1 중간 검증 +```sh +$ command -v java +(output) + +$ cd apps/flutter-test/android && ./gradlew --version +(output) + +$ cd apps/flutter-test/android && ./gradlew testDebugUnitTest +(output) +``` + +### 최종 검증 +```sh +$ command -v java +(output) + +$ cd apps/flutter-test/android && ./gradlew --version +(output) + +$ cd apps/flutter-test/android && ./gradlew testDebugUnitTest +(output) +``` + +--- + +> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?** +> If anything is blank, go back and fill it in before saving this file. +> Leave review-agent-only sections unchanged. + +Sections and their ownership: + +| Section | Owner | Note | +|---------|-------|------| +| Header comment, 개요, 리뷰 에이전트 지시 | Fixed at stub creation | Implementing agent must not modify or execute these | +| 구현 항목별 완료 여부 (item names) | Fixed at stub creation | Implementing agent checks `[ ]` -> `[x]` only | +| 구현 체크리스트 (item text/order) | Fixed at stub creation from plan | Implementing agent checks `[ ]` -> `[x]` only | +| 코드리뷰 전용 체크리스트 | Review agent only | Implementing agent must not modify or check this section | +| 계획 대비 변경 사항, 주요 설계 결정 | Implementing agent | Replace placeholder text with actual content | +| 사용자 리뷰 요청 | Implementing agent | Keep `상태: 없음` unless user input is required | +| 리뷰어를 위한 체크포인트 | Fixed at stub creation | Pre-filled from plan | +| 검증 결과 | Implementing agent | Fill command output only | diff --git a/agent-task/m-client-validation/02_native_test/PLAN-cloud-G07.md b/agent-task/m-client-validation/02_native_test/PLAN-cloud-G07.md new file mode 100644 index 00000000..39b4ef2c --- /dev/null +++ b/agent-task/m-client-validation/02_native_test/PLAN-cloud-G07.md @@ -0,0 +1,119 @@ + + +# Android Native Unit Test Plan + +## 이 파일을 읽는 구현 에이전트에게 + +`CODE_REVIEW-cloud-G07.md`의 구현 에이전트 소유 섹션을 채우는 것이 구현의 마지막 단계다. 검증을 실제로 실행하고, 실제 stdout/stderr를 기록하고, active 파일을 그대로 둔 채 리뷰 준비를 보고한다. 사용자 결정, 외부 Android SDK 준비, 또는 범위 충돌로 막히면 review stub의 `사용자 리뷰 요청` 섹션에 정확한 근거와 재개 조건을 적고 멈춘다. `USER_REVIEW.md`, archive log, `complete.log` 작성은 code-review 전용이다. + +## 배경 + +현재 Milestone `클라이언트 검증 기준선`의 `test-host` Epic에는 `native-test` 검증이 남아 있다. 이 작업은 `apps/flutter-test/android`에서 플러그인의 Android native unit test가 실행되는지 확인한다. Android SDK와 Gradle 환경 의존성이 있어 작은 문서 정리와 분리해 계획 작업으로 둔다. + +## 사용자 리뷰 요청 흐름 + +구현 중 차단 조건은 active `CODE_REVIEW-cloud-G07.md`의 `사용자 리뷰 요청` 섹션에 기록한다. 형식은 `agent-ops/skills/common/_templates/implementation-user-review-request-section.md`를 따른다. code-review가 정당성을 검증한 뒤 실제 `USER_REVIEW.md` 작성 여부를 결정한다. + +## 분석 결과 + +### 읽은 파일 + +- `agent-roadmap/current.md` +- `agent-roadmap/phase/product-foundation/PHASE.md` +- `agent-roadmap/phase/product-foundation/milestones/client-validation.md` +- `agent-ops/rules/project/domain/client-app/rules.md` +- `agent-ops/rules/project/domain/messaging-flutter/rules.md` +- `apps/flutter-test/README.md` +- `apps/flutter-test/android/settings.gradle.kts` +- `apps/flutter-test/android/build.gradle.kts` +- `apps/flutter-test/android/app/build.gradle.kts` +- `apps/flutter-test/android/app/src/main/AndroidManifest.xml` +- `apps/flutter-test/pubspec.yaml` +- `packages/messaging_flutter/README.md` +- `packages/messaging_flutter/docs/android-test-environment.md` +- `packages/messaging_flutter/android/build.gradle.kts` +- `packages/messaging_flutter/android/src/main/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPlugin.kt` +- `packages/messaging_flutter/android/src/test/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPluginTest.kt` + +### 테스트 커버리지 공백 + +- Gradle execution path: `apps/flutter-test/README.md:79` documents `./gradlew testDebugUnitTest`, but active task evidence is still needed. +- Native plugin method handling: `packages/messaging_flutter/android/src/test/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPluginTest.kt:28` covers invalid `debugSendNativeEvent`; `:61`, `:93`, `:125`, and `:157` cover argument validation for token/auth/signing/clear flows. +- Intent payload behavior: `NexoMessagingPluginTest.kt:201` through `:245` covers null, empty, default opened type, explicit type, and user interaction. +- Storage, ACK request behavior, notification rendering, inline reply, and dismiss receiver coverage are still broader future native-test gaps; this plan does not expand them because the current roadmap item asks for execution procedure and `testDebugUnitTest` success. + +### 심볼 참조 + +none. 이 계획은 rename/remove 작업을 포함하지 않는다. + +### 분할 판단 + +Split decision policy was evaluated before choosing plan files. Shared task group: `agent-task/m-client-validation/`. This subtask is `02_native_test` and has no runtime dependency. Sibling `01_integration_path` is independent because it validates Flutter device/emulator integration rather than Gradle unit test execution. + +### 범위 결정 근거 + +이 계획은 `test-host` Epic의 `[native-test]`만 다룬다. Flutter host integration은 `01_integration_path`에서 분리한다. Native coverage expansion for storage/ACK/notification/reply/dismiss is noted as a gap but excluded because the active roadmap item only requires maintaining the Android native unit test execution procedure and command success. + +### 빌드 등급 + +build=`cloud-G07`, review=`cloud-G07`. Android SDK, Flutter Gradle plugin wiring, and Gradle output classification are success criteria, so terminal/toolchain diagnosis is required. + +## 구현 체크리스트 + +- [ ] Android SDK/Gradle preflight를 확인하고, 없으면 `사용자 리뷰 요청`에 실제 출력과 재개 조건을 기록한다. +- [ ] `cd apps/flutter-test/android && ./gradlew testDebugUnitTest`가 Android SDK 환경에서 성공하도록 확인한다. 실패가 제품 결함이면 이 계획의 파일 경계 안에서 최소 수정 후 같은 명령을 재실행한다. +- [ ] Native unit test coverage gaps are not expanded unless the command reveals a failing product behavior in the existing tests. +- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +### [TEST-1] Android Gradle native unit test execution + +#### 문제 + +`apps/flutter-test/README.md:79` and `packages/messaging_flutter/README.md:215` document `./gradlew testDebugUnitTest`. The app Gradle wrapper reads Flutter SDK metadata through `apps/flutter-test/android/settings.gradle.kts:1`, while plugin unit tests are configured by `packages/messaging_flutter/android/build.gradle.kts:45` and `:58`. The native tests exist in `packages/messaging_flutter/android/src/test/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPluginTest.kt:14`, but this Milestone still needs execution evidence from an Android SDK environment. + +#### 해결 방법 + +기본 구현은 Gradle native unit test 실행과 결과 기록이다. 코드 변경은 계획하지 않는다. `SDK location not found`, missing Flutter SDK metadata, or missing Android SDK는 제품 코드 수정으로 처리하지 않고 환경 blocker로 기록한다. 기존 테스트가 제품 결함을 노출하면 아래 파일 경계 안에서 최소 수정한다. + +#### 수정 파일 및 체크리스트 + +- [ ] `packages/messaging_flutter/android/src/test/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPluginTest.kt`는 기존 unit coverage를 유지한다. +- [ ] `packages/messaging_flutter/android/src/main/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPlugin.kt`는 기존 test failure가 plugin 결함을 가리킬 때만 수정한다. +- [ ] `packages/messaging_flutter/android/build.gradle.kts`는 test sourceSet/testOptions/dependencies 결함이 확인된 경우에만 수정한다. +- [ ] `apps/flutter-test/android/settings.gradle.kts`와 `apps/flutter-test/android/app/build.gradle.kts`는 Flutter/Android Gradle wiring 결함이 확인된 경우에만 수정한다. + +#### 테스트 작성 + +새 테스트 작성은 기본 계획에서 제외한다. 현재 unit tests가 roadmap의 native test 실행 경로를 검증하기 위한 대상이다. 명령 실패가 기존 tests로 표현되지 않는 regression을 드러내면 `NexoMessagingPluginTest.kt`에 해당 regression test를 추가하고 같은 Gradle command로 검증한다. + +#### 중간 검증 + +```sh +command -v java +cd apps/flutter-test/android && ./gradlew --version +cd apps/flutter-test/android && ./gradlew testDebugUnitTest +``` + +예상 결과: `./gradlew --version`과 `./gradlew testDebugUnitTest`가 성공한다. Android SDK 또는 Flutter SDK metadata가 없으면 제품 실패로 고치지 말고 `사용자 리뷰 요청`에 실제 출력과 필요한 환경을 기록한다. + +## 수정 파일 요약 + +| 파일 | 항목 | +| --- | --- | +| `packages/messaging_flutter/android/src/test/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPluginTest.kt` | TEST-1 | +| `packages/messaging_flutter/android/src/main/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPlugin.kt` | TEST-1 | +| `packages/messaging_flutter/android/build.gradle.kts` | TEST-1 | +| `apps/flutter-test/android/settings.gradle.kts` | TEST-1 | +| `apps/flutter-test/android/app/build.gradle.kts` | TEST-1 | + +## 최종 검증 + +```sh +command -v java +cd apps/flutter-test/android && ./gradlew --version +cd apps/flutter-test/android && ./gradlew testDebugUnitTest +``` + +검색/생성 출력 검증은 없다. Gradle build cache 결과는 이 계획의 성공 판정에 사용하지 않는다. + +모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다. diff --git a/apps/flutter-test/README.md b/apps/flutter-test/README.md index e7cbf060..cde7a08d 100644 --- a/apps/flutter-test/README.md +++ b/apps/flutter-test/README.md @@ -22,6 +22,13 @@ The app is a plugin API consumer and verification host. Native push handling, ACK delivery, token/key storage, notification rendering, inline reply, and dismiss handling remain owned by `packages/messaging_flutter`. +## Thin Host Contract + +The host UI should expose only the plugin integration state needed by tests: +device token, raw notification event, opened notification event, and routing +callback state. `test/widget_test.dart` protects this contract by asserting the +four status lines remain present and product-style controls are not added. + ## Structure ```text @@ -65,6 +72,10 @@ flutter test flutter test integration_test ``` +Use `flutter test` for the thin-host contract and `flutter test +integration_test` for real Flutter host registration, method-channel, +event-channel, and opened-routing coverage. + Run Android native unit tests from `apps/flutter-test/android`: ```sh diff --git a/packages/messaging_flutter/README.md b/packages/messaging_flutter/README.md index dbfc41c8..f5d2d48c 100644 --- a/packages/messaging_flutter/README.md +++ b/packages/messaging_flutter/README.md @@ -229,6 +229,11 @@ Use deterministic tests for repository-owned behavior. The example integration test can inject a debug native event through the plugin method channel so the EventChannel and opened-routing path can run without Firebase FCM. +The Android implementation remains a nexo-owned embedded SDK surface in these +tests. Test coverage should follow the server/push contract, Android and FCM +platform behavior, and Flutter plugin registration rather than the Mattermost +mobile app source tree. + Use the repository tests as the source of truth for plugin behavior: 1. Root `test/` covers Dart API behavior, event parsing, callback routing, and