chore(roadmap): Flutter Web 알림 Smoke 마일스톤을 검토중 동기화한다

웹 smook 테스트 분리, helper 경로, 수동 증빙 정리를 통해 마일스톤 완료 근거를 milestone 기준으로 반영해 로드맵 상태를 검토중으로 맞췄다.
This commit is contained in:
toki 2026-06-08 19:58:45 +09:00
parent e2823b38e0
commit 8ff55d4940
19 changed files with 1296 additions and 136 deletions

View file

@ -76,6 +76,7 @@ Postgres를 host에 publish하지 않고 compose network 내부 `db:5432`로만
| 서버 Go 테스트 포함 | `NEXO_CORE_GO_TEST=1 bin/test` | 로컬 `go`가 필요하다. |
| 서버 Go vet 포함 | `NEXO_CORE_GO_LINT=1 bin/lint` | 로컬 `go`가 필요하다. |
| 서버 Go build 포함 | `NEXO_CORE_GO_BUILD=1 bin/build` | 로컬 `go`가 필요하다. |
| Flutter Web/Chrome 테스트 포함 | `NEXO_FLUTTER_WEB_TEST=1 bin/test` | `packages/messaging_flutter`에서 `flutter test --platform chrome`을 실행한다. Flutter Chrome test 환경이 필요하다. |
| `flutter-test` 호스트 직접 실행 | `cd apps/flutter-test && flutter run` | Flutter SDK가 필요하다. |
| 플러그인 직접 테스트 | `cd packages/messaging_flutter && flutter test` | Flutter SDK가 필요하다. |
| Android 네이티브 단위 테스트 실행 | `cd apps/flutter-test/android && ./gradlew testDebugUnitTest` | Android SDK가 필요하다. |
@ -153,6 +154,7 @@ Deployment Loop를 따른다.
| `NEXO_CORE_GO_TEST` | `bin/test`에서 서버 Go 테스트를 실행한다. | `0` |
| `NEXO_CORE_GO_LINT` | `bin/lint`에서 서버 Go vet을 실행한다. | `0` |
| `NEXO_CORE_GO_BUILD` | `bin/build`에서 서버 Go build를 실행한다. | `0` |
| `NEXO_FLUTTER_WEB_TEST` | `bin/test`에서 `packages/messaging_flutter` Chrome/web 테스트를 실행한다. | `0` |
## 참고 문서

View file

@ -40,7 +40,7 @@ Mattermost server/webapp/push-proxy는 upstream-followable runtime으로 두고,
- [완료] Flutter Web 알림
- 경로: `agent-roadmap/archive/phase/messaging-runtime/milestones/flutter-web-notification.md`
- 요약: `packages/messaging_flutter`를 Flutter Web/Chrome foreground browser notification까지 확장하고, Full Web Push는 별도 후속 계약으로 분리한다.
- [계획] Flutter Web 알림 Smoke 보완
- [검토중] Flutter Web 알림 Smoke 보완
- 경로: `agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md`
- 요약: Flutter Web foreground browser notification smoke가 원격 web runner와 forwarded localhost URL에서 실제로 재현되도록 host scaffold, Chrome 테스트, 수동 evidence 기준을 보완한다.
- [계획] iOS 알림 테스트

View file

@ -12,7 +12,7 @@ Flutter Web foreground browser notification이 실제 브라우저 환경에서
## 상태
[계획]
[검토중]
## 승격 조건
@ -36,27 +36,31 @@ Flutter Web foreground browser notification이 실제 브라우저 환경에서
Flutter Web 알림 smoke가 실제 브라우저에서 열릴 수 있도록 test host와 실행 경계를 만든다.
- [ ] [web-scaffold] `apps/flutter-test`에 Flutter Web scaffold를 추가하고 web build가 통과하도록 구성한다. 검증: 원격 runner에서 `apps/flutter-test` web build가 성공해야 한다.
- [ ] [web-runtime] 원격 Flutter Web server와 forwarded localhost URL 기반 수동 smoke 절차를 정리한다. 검증: 사용자가 forwarded URL에서 permission 요청, notification display, click/open routing 상태를 확인할 수 있어야 한다.
- [x] [web-scaffold] `apps/flutter-test`에 Flutter Web scaffold를 추가하고 web build가 통과하도록 구성한다. 검증: 원격 runner에서 `apps/flutter-test` web build가 성공해야 한다.
- [x] [web-runtime] 원격 Flutter Web server와 forwarded localhost URL 기반 수동 smoke 절차를 정리한다. 검증: 사용자가 forwarded URL에서 permission 요청, notification display, click/open routing 상태를 확인할 수 있어야 한다.
### Epic: [web-tests] Web 검증 분리
VM 단위 테스트와 Chrome/web 테스트가 서로 다른 platform expectation을 올바르게 검증하도록 나눈다.
- [ ] [chrome-tests] `packages/messaging_flutter`의 Chrome/web 테스트가 web runtime에서는 browser notification support를 기대하고, VM 테스트는 non-web unsupported를 기대하도록 분리한다. 검증: 원격 runner에서 package Chrome 테스트가 통과해야 한다.
- [ ] [helper-route] workspace helper 또는 테스트 규칙에 web build/smoke opt-in 경로를 추가해 `bin/test`만으로 web smoke가 완료된 것처럼 보이지 않게 한다. 검증: web 검증을 생략한 경우 skip 또는 미실행 사유가 명확히 보고되어야 한다.
- [x] [chrome-tests] `packages/messaging_flutter`의 Chrome/web 테스트가 web runtime에서는 browser notification support를 기대하고, VM 테스트는 non-web unsupported를 기대하도록 분리한다. 검증: 원격 runner에서 package Chrome 테스트가 통과해야 한다.
- [x] [helper-route] workspace helper 또는 테스트 규칙에 web build/smoke opt-in 경로를 추가해 `bin/test`만으로 web smoke가 완료된 것처럼 보이지 않게 한다. 검증: web 검증을 생략한 경우 skip 또는 미실행 사유가 명확히 보고되어야 한다.
### Epic: [evidence] 완료 Evidence
완료 판정이 fake interop 단위 테스트에만 기대지 않도록 browser evidence 기준을 남긴다.
- [ ] [manual-evidence] browser notification permission/display/click 수동 smoke evidence 기준을 민감값 없이 정리한다. 검증: 완료 리뷰에 원격 실행 명령, 사용자 확인 결과, 생략된 Full Web Push 범위가 함께 남아야 한다.
- [x] [manual-evidence] browser notification permission/display/click 수동 smoke evidence 기준을 민감값 없이 정리한다. 검증: 완료 리뷰에 원격 실행 명령, 사용자 확인 결과, 생략된 Full Web Push 범위가 함께 남아야 한다.
## 완료 리뷰
- 상태: 없음
- 요청일: 없음
- 완료 근거: 없음
- 상태: 요청됨
- 요청일: 2026-06-08
- 완료 근거:
- `agent-task/archive/2026/06/m-flutter-web-notification-smoke/01_web_scaffold/complete.log`
- `agent-task/archive/2026/06/m-flutter-web-notification-smoke/02+01_web_runtime/complete.log`
- `agent-task/archive/2026/06/m-flutter-web-notification-smoke/03_chrome_tests/complete.log`
- `agent-task/archive/2026/06/m-flutter-web-notification-smoke/04+03_manual_evidence_closeout/complete.log`
- 리뷰 필요:
- [ ] 사용자가 완료 결과를 확인했다
- [ ] archive 이동을 승인했다
@ -75,4 +79,4 @@ VM 단위 테스트와 Chrome/web 테스트가 서로 다른 platform expectatio
- 표준선(선택): 실제 host, port, credential, 포워딩 명령 원문은 tracked roadmap/docs에 쓰지 않고 ignored local test environment 문서 또는 사용자 제공 환경 기준에서 확인한다.
- 선행 작업: Flutter Web 알림
- 후속 작업: Full Web Push platform 계약
- 확인 필요: 원격 runner에서 Chrome/web device와 사용자가 접근 가능한 forwarded localhost URL을 함께 열어 실제 browser permission/display/click evidence를 남긴다.
- 확인 필요: `web-scaffold`, `web-runtime`, `helper-route` evidence는 완료됐다. 남은 확인은 Chrome/web test 분리와 수동 evidence 기준 closeout이다.

View file

@ -0,0 +1,52 @@
# User Review Resolved - m-flutter-web-notification-smoke/02+01_web_runtime
## 요청 일시
2026-06-08
## 상태
RESOLVED_PASS
## 사유
- 유형: environment-blocked
- 현재 리뷰 회차: 1
- 최종 판정: PASS
- 요약: Flutter Web build와 forwarded preview URL reachability가 통과했고, 사용자가 forwarded browser에서 permission/display/click action evidence를 확인해 USER_REVIEW 차단이 해소됐다.
## 루프 이력
| Plan | Review | Verdict | 메모 |
|------|--------|---------|------|
| `plan_cloud_G07_0.log` | `code_review_cloud_G07_0.log` | FAIL | 사용자 browser evidence가 남아 있어 PASS로 닫을 수 없다. |
| `USER_REVIEW.md` | user decision | PASS/RESOLVED | 사용자가 4번까지 정상 확인했고, macOS 알림센터에 알림이 표시되었으며, 해당 알림 클릭 후 action이 동작했다고 확인했다. |
## 차단 근거
- 문제: `agent-test/local/runtime-env.md`의 web smoke 판정 기준은 browser permission/display/click evidence를 사용자가 forwarded browser에서 확인해야 통과로 본다.
- 현재 archive plan: `plan_cloud_G07_0.log`
- 현재 archive review: `code_review_cloud_G07_0.log`
- 검증 명령: `flutter build web`, `curl -fsS ${NEXO_BROWSER_PREVIEW_URL} >/dev/null`
- 실제 출력: 리뷰 중 remote/container `flutter build web` 재실행은 `Built build/web`로 통과했고, forwarded preview GET 재확인은 `reachability ok`로 통과했다. 환경값 원문은 출력하지 않았다.
- 차단 판단 근거: terminal-only agent는 브라우저 알림 권한 prompt를 승인하거나, visible notification 표시와 실제 notification click 후 앱 상태 변화를 대신 관찰할 수 없다.
- 해소 근거: 사용자가 forwarded browser smoke에서 4번까지 정상 확인했고, macOS 알림센터에 알림이 표시되었으며, 알림 클릭 후 action 동작까지 확인했다고 보고했다. 이는 남아 있던 browser permission/display/click evidence를 충족한다.
## 사용자 결정 필요
- [x] `agent-test/local/web-smoke.env``NEXO_BROWSER_PREVIEW_URL`을 forwarded localhost URL로 열고 browser smoke controls를 실행한다.
- [x] `Refresh web permission`, `Request web permission`, `Show web smoke notification` 실행 후 browser permission/display/click action 결과를 확인한다.
- [ ] 브라우저 확인이 불가능하면 자동 follow-up plan/review를 계속 진행할지, 계획을 재작성할지, 작업을 보류할지 결정한다.
## 재개 조건
- 충족됨: 사용자가 forwarded browser smoke와 macOS 알림센터 click action을 확인했다.
## 다음 실행 힌트
- `complete.log`를 작성하고 task directory를 archive로 이동한다.
## 종료 규칙
- 사용자가 이 stop state를 완료/PASS로 해소하면 `USER_REVIEW.md`를 해소 상태로 갱신하고, `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다.
- 새 구현이 필요하면 `plan` 스킬이 `USER_REVIEW.md``user_review_N.log`로 아카이브한 뒤 새 `PLAN-*-G??.md` / `CODE_REVIEW-*-G??.md`를 작성한다.

View file

@ -0,0 +1,193 @@
<!-- task=m-flutter-web-notification-smoke/02+01_web_runtime plan=0 tag=WEB-RUNTIME -->
# Code Review Reference - WEB-RUNTIME
> **[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, user-owned 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`.
> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only.
## 개요
date=2026-06-08
task=m-flutter-web-notification-smoke/02+01_web_runtime, plan=0, tag=WEB-RUNTIME
## Roadmap Targets
- Milestone: `agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md`
- Task ids:
- `web-runtime`: 원격 Flutter Web server와 forwarded localhost URL 기반 수동 smoke 절차를 정리한다.
- Completion mode: check-on-pass
## 이 파일을 읽는 리뷰 에이전트에게
> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.
각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요. PASS이고 task group이 `m-<milestone-slug>`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
---
## 구현 항목별 완료 여부
| 항목 | 완료 여부 |
|------|---------|
| [WEB-RUNTIME-1] Predecessor gate | [x] |
| [WEB-RUNTIME-2] Ignored remote preview environment contract | [x] |
| [WEB-RUNTIME-3] README smoke procedure 연결 | [x] |
| [WEB-RUNTIME-4] Remote server reachability and user evidence handoff | [x] |
## 구현 체크리스트
- [x] `01_web_scaffold` predecessor complete log를 확인한다.
- [x] remote preview 실행에 필요한 ignored environment variable contract를 `agent-test/local/runtime-env.md` 또는 별도 ignored profile에 정리한다.
- [x] `apps/flutter-test/README.md`에 web runtime smoke 절차를 환경값 없이 연결한다.
- [x] 원격 preview server reachability를 검증하고 사용자 browser smoke evidence 수집 조건을 기록한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
## 코드리뷰 전용 체크리스트
> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [x] active `CODE_REVIEW-*-G??.md`를 `code_review_cloud_G07_0.log`로 아카이브한다.
- [x] active `PLAN-*-G??.md`를 `plan_cloud_G07_0.log`로 아카이브한다.
- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다.
- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [ ] PASS이면 active task 디렉터리 `agent-task/{task_name}/`를 `agent-task/archive/YYYY/MM/{task_name}/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [ ] PASS이고 task group이 `m-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/{task_group}/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-{build_lane}-GNN.md`와 `CODE_REVIEW-{review_lane}-GNN.md`를 작성하고 `complete.log`를 작성하지 않는다.
- [x] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다.
- [x] USER_REVIEW가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다.
## 구현 에이전트 기록
### 변경 요약
- `01_web_scaffold` predecessor complete log가 archive에 정확히 1개 있음을 확인했다.
- ignored local profile `agent-test/local/web-smoke.env`를 추가해 remote/container/forwarded preview 값을 tracked 파일 밖에서 주입하게 했다.
- ignored local test 문서 `agent-test/local/runtime-env.md`에 Flutter Web preview 변수 contract, build/server/reachability 명령, GET reachability 판정, browser evidence 기준을 보강했다.
- `apps/flutter-test/README.md`에 web build, remote web-server 실행, forwarded URL reachability, browser permission/display/click 확인 절차를 환경값 없이 연결했다.
- 현재 checkout의 Flutter Web server를 preview container 안에서 detached로 띄웠고, host-side forwarded URL GET reachability를 확인했다.
### 계획 대비 변경 사항
- 계획의 `curl -fsSI ${NEXO_BROWSER_PREVIEW_URL}` HEAD 검증은 Flutter web-server가 root HEAD에 `404 Not Found`를 반환해 통과 기준으로 쓰지 않았다. browser 접근과 같은 GET root는 HTML을 반환하므로, runtime-env/README reachability 기준을 `curl -fsS ${NEXO_BROWSER_PREVIEW_URL} >/dev/null`로 바꿨다.
- preview server는 interactive shell을 점유하지 않도록 `setsid` detached process로 실행했다.
### 검증 결과
```sh
find agent-task/m-flutter-web-notification-smoke -maxdepth 2 -path '*/01_*/*' -name complete.log -print
find agent-task/archive -path '*/m-flutter-web-notification-smoke/01_*/complete.log' -print
```
```text
agent-task/archive/2026/06/m-flutter-web-notification-smoke/01_web_scaffold/complete.log
```
```sh
set -a; source agent-test/local/web-smoke.env; set +a
test -n "$NEXO_REMOTE_SSH"
test -n "$NEXO_PREVIEW_CONTAINER"
test -n "$NEXO_CONTAINER_REPO"
test -n "$NEXO_WEB_HOSTNAME"
test -n "$NEXO_CONTAINER_WEB_PORT"
test -n "$NEXO_BROWSER_PREVIEW_URL"
```
```text
PASS: all required variables were non-empty. Values were not printed.
```
```sh
git check-ignore -v agent-test/local/web-smoke.env agent-test/local/runtime-env.md agent-test/runs/example.log
```
```text
.gitignore:30:agent-test/local/ agent-test/local/web-smoke.env
.gitignore:30:agent-test/local/ agent-test/local/runtime-env.md
.gitignore:31:agent-test/runs/ agent-test/runs/example.log
```
```sh
set -a; source agent-test/local/web-smoke.env; set +a
ssh "$NEXO_REMOTE_SSH" "zsh -lc 'docker exec ${NEXO_PREVIEW_CONTAINER} sh -lc \"cd ${NEXO_CONTAINER_REPO}/apps/flutter-test && flutter build web\"'"
```
```text
Compiling lib/main.dart for the Web...
Wasm dry run succeeded. Consider building and testing your application with the `--wasm` flag.
Compiling lib/main.dart for the Web... 27.0s
Built build/web
```
```sh
set -a; source agent-test/local/web-smoke.env; set +a
cd "$NEXO_CONTAINER_REPO/apps/flutter-test"
setsid sh -lc 'flutter run -d web-server --web-hostname "$0" --web-port "$1" > /tmp/nexo-web-smoke.log 2>&1' "$NEXO_WEB_HOSTNAME" "$NEXO_CONTAINER_WEB_PORT" &
```
```text
PASS: preview server opened $NEXO_CONTAINER_WEB_PORT.
/tmp/nexo-web-smoke.log excerpt:
Launching lib/main.dart on Web Server in debug mode...
Waiting for connection from debug service on Web Server...
lib/main.dart is being served at http://$NEXO_WEB_HOSTNAME:$NEXO_CONTAINER_WEB_PORT
```
```sh
set -a; source agent-test/local/web-smoke.env; set +a
ssh "$NEXO_REMOTE_SSH" "zsh -lc 'curl -fsS ${NEXO_BROWSER_PREVIEW_URL} >/dev/null'"
```
```text
PASS: forwarded preview URL returned the Flutter Web HTML document by HTTP GET.
```
```sh
rg --sort path -n "web-smoke|NEXO_BROWSER_PREVIEW_URL|forwarded localhost|Last web display|Last opened|Last navigation" agent-test/local/runtime-env.md apps/flutter-test/README.md
```
```text
PASS: runtime-env and README contain the web smoke profile, reachability command, and browser evidence checklist without raw environment values.
```
### 남은 위험
- Browser notification permission prompt, visible notification display, and notification click/open routing still require a user-opened forwarded browser. Terminal-only verification cannot complete those UI evidence items.
## 사용자 리뷰 요청
_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 구현 에이전트는 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._
- 상태: 필요
- 사유 유형: 사용자 소유 browser evidence
- 결정 필요: 없음
- 차단 근거: Flutter Web build와 forwarded URL GET reachability는 통과했고 preview server는 detached로 실행 중이다. 그러나 browser permission prompt, visible notification display, notification click 후 `Last opened`/`Last navigation` 상태는 사용자가 forwarded localhost URL을 브라우저에서 열어야 확인할 수 있다.
- 실행한 검증/명령: `01_web_scaffold` complete log 확인, `agent-test/local/web-smoke.env` 변수 non-empty 확인, `git check-ignore` 확인, remote/container `flutter build web`, detached `flutter run -d web-server`, host-side `curl -fsS ${NEXO_BROWSER_PREVIEW_URL} >/dev/null`, README/runtime-env `rg` 확인.
- 자동 후속 불가 이유: 브라우저 알림 권한 UI와 visible notification click은 terminal-only agent가 관찰하거나 대신 승인할 수 없다.
- 재개 조건: 사용자가 `agent-test/local/web-smoke.env`의 `NEXO_BROWSER_PREVIEW_URL`을 forwarded localhost URL로 열고, `Refresh web permission`, `Request web permission`, `Show web smoke notification`, notification click 후 `Last web display`, `Last opened`, `Last navigation` 결과를 확인한다.
## 코드리뷰 결과
_리뷰 에이전트가 판정을 append한다._
### 코드리뷰 결과 - 2026-06-08
- 종합 판정: FAIL
- 차원별 평가:
- correctness: Pass
- completeness: Fail
- test coverage: Pass
- API contract: Pass
- code quality: Pass
- plan deviation: Pass
- verification trust: Fail
- 발견된 문제:
- Required: `agent-test/local/runtime-env.md:114`의 판정 기준은 browser permission/display/click을 사용자가 forwarded browser에서 확인한 evidence가 있어야 통과로 본다. 현재 구현 로그도 `code_review_cloud_G07_0.log:160` 및 `code_review_cloud_G07_0.log:171`에서 해당 browser evidence가 남아 있지 않다고 명시하므로, 사용자가 forwarded URL을 열어 `Last web display`, `Last opened`, `Last navigation` 결과를 확인하고 그 evidence로 stop state를 해소해야 한다.
- 다음 단계: USER_REVIEW - active plan/review를 log로 아카이브하고 `USER_REVIEW.md`를 작성해 사용자 browser evidence 확인을 기다린다.

View file

@ -0,0 +1,47 @@
# Complete - m-flutter-web-notification-smoke/02+01_web_runtime
## 완료 일시
2026-06-08
## 요약
Flutter Web remote runtime smoke를 1회 리뷰했고, 사용자 브라우저 evidence로 USER_REVIEW 차단을 해소해 최종 PASS로 완료했다.
## 루프 이력
| Plan | Review | Verdict | 메모 |
|------|--------|---------|------|
| `plan_cloud_G07_0.log` | `code_review_cloud_G07_0.log` | FAIL | remote web build와 preview reachability는 통과했지만 사용자 browser permission/display/click evidence가 남아 있었다. |
| `USER_REVIEW.md` | user decision | PASS/RESOLVED | 사용자가 4번까지 정상 확인했고, macOS 알림센터에 알림 표시 및 알림 클릭 후 action 동작을 확인했다. |
## 구현/정리 내용
- `apps/flutter-test/README.md`에 ignored local preview profile 기반 Flutter Web remote smoke 절차를 환경값 없이 연결했다.
- `agent-test/local/runtime-env.md`의 ignored local contract와 web smoke 판정 기준을 확인했다.
- remote/container `flutter build web`과 forwarded preview URL GET reachability를 확인했다.
- 사용자 확인으로 browser notification permission/display/click action evidence를 충족했다.
## 최종 검증
- `find agent-task/archive -path '*/m-flutter-web-notification-smoke/01_*/complete.log' -print` - PASS; predecessor `01_web_scaffold` complete log가 정확히 하나 확인됐다.
- `test -n` checks for `NEXO_REMOTE_SSH`, `NEXO_PREVIEW_CONTAINER`, `NEXO_CONTAINER_REPO`, `NEXO_WEB_HOSTNAME`, `NEXO_CONTAINER_WEB_PORT`, `NEXO_BROWSER_PREVIEW_URL` - PASS; required variables were non-empty and raw values were not printed.
- `git check-ignore -v agent-test/local/web-smoke.env agent-test/local/runtime-env.md agent-test/runs/example.log` - PASS; local environment/profile artifacts are ignored.
- `ssh ... flutter build web` - PASS; `Built build/web`.
- `ssh ... curl -fsS ${NEXO_BROWSER_PREVIEW_URL} >/dev/null` - PASS; forwarded preview GET returned successfully.
- 사용자 browser smoke - PASS; 4번까지 정상 확인, macOS 알림센터 알림 표시 확인, 알림 클릭 후 action 동작 확인.
## Roadmap Completion
- Milestone: `agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md`
- Completed task ids:
- `web-runtime`: PASS; evidence=`plan_cloud_G07_0.log`, `code_review_cloud_G07_0.log`, `USER_REVIEW.md`; verification=`flutter build web`, forwarded preview GET reachability, user browser permission/display/click action evidence
- Not completed task ids: 없음
## 잔여 Nit
- 없음
## 후속 작업
- 없음

View file

@ -0,0 +1,202 @@
<!-- task=m-flutter-web-notification-smoke/03_chrome_tests plan=0 tag=CHROME-TESTS -->
# Code Review Reference - CHROME-TESTS
> **[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, user-owned 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`. Evidence gaps that a follow-up agent can close by rerunning commands or collecting artifacts are normal follow-up issues, not user-review blockers by themselves.
> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation; record the needed decision in `사용자 리뷰 요청` and stop for code-review.
> 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-06-08
task=m-flutter-web-notification-smoke/03_chrome_tests, plan=0, tag=CHROME-TESTS
## Roadmap Targets
- Milestone: `agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md`
- Task ids:
- `chrome-tests`: `packages/messaging_flutter`의 Chrome/web 테스트가 web runtime에서는 browser notification support를 기대하고, VM 테스트는 non-web unsupported를 기대하도록 분리한다.
- Completion mode: check-on-pass
## 이 파일을 읽는 리뷰 에이전트에게
> **[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-flutter-web-notification-smoke/03_chrome_tests/`로 이동한다. WARN/FAIL이면 user-review gate를 확인한 뒤 다음 active plan/review 파일 또는 `USER_REVIEW.md`를 작성한다.
4. PASS이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.
---
## 구현 항목별 완료 여부
| 항목 | 완료 여부 |
|------|---------|
| [CHROME-TESTS-1] VM-only permission tests 분리 | [x] |
| [CHROME-TESTS-2] Chrome/browser tests 추가 | [x] |
| [CHROME-TESTS-3] Opt-in route 전체 검증 | [x] (VM+helper PASS; Chrome 실행 불가 — cloud runner 필요) |
## 구현 체크리스트
- [x] VM-only unsupported web permission assertions are isolated so `flutter test` still proves non-web unsupported behavior.
- [x] Chrome/web tests are added so browser Notification support/current permission behavior is verified without prompting the user.
- [x] `NEXO_FLUTTER_WEB_TEST=1 bin/test` or `flutter test --platform chrome` is run in a Chrome-capable environment and records real stdout/stderr. — review rerun used `CHROME_EXECUTABLE=/config/.cache/ms-playwright/chromium-1178/chrome-linux/chrome` and passed.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
## 코드리뷰 전용 체크리스트
> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다.
- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [x] active `CODE_REVIEW-*-G??.md`를 `code_review_cloud_G07_N.log`로 아카이브한다.
- [x] active `PLAN-*-G??.md`를 `plan_cloud_G07_M.log`로 아카이브한다.
- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다.
- [x] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [x] PASS이면 active task 디렉터리 `agent-task/{task_name}/`를 `agent-task/archive/YYYY/MM/{task_name}/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [x] PASS이고 task group이 `m-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [x] PASS split 작업이면 이동 후 빈 active parent `agent-task/{task_group}/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-{build_lane}-GNN.md`와 `CODE_REVIEW-{review_lane}-GNN.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로 이동한다.
## 계획 대비 변경 사항
없음.
## 주요 설계 결정
- `nexo_messaging_vm_test.dart`에 `@TestOn('vm')` 어노테이션을 파일 상단에 두어 `flutter test` (VM) 실행 시에만 포함되도록 했다.
- `nexo_messaging_web_test.dart`에 `@TestOn('browser')` 어노테이션을 파일 상단에 두어 `--platform chrome` 실행 시에만 포함되도록 했다. `requestPermission()` 호출은 포함하지 않아 permission prompt 없이 현재 상태만 검증한다.
- shared `nexo_messaging_test.dart`에서 `NexoMessagingPlugin web notification permission` group 전체를 제거하고 VM-only 파일로 이동했다. 이 group의 non-web unsupported 기대값이 Chrome 실행 시 browser Notification support와 충돌하기 때문이다.
## 사용자 리뷰 요청
_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 구현 에이전트는 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._
- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음
## 리뷰어를 위한 체크포인트
- VM-only unsupported permission assertions must not run as Chrome browser expectations.
- Chrome tests must avoid permission prompts and verify current support/status only.
- `NEXO_FLUTTER_WEB_TEST=1 bin/test` must pass in a Chrome-capable environment, not merely report local Chrome absence.
## 검증 결과
_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._
필수 규칙:
- 검증 명령은 고정된 계약이다. 임의로 대체하지 않는다.
- 대체가 필요하면 `계획 대비 변경 사항`에 이유와 대체 명령을 기록한다.
- `검증 결과`에는 실제 stdout/stderr를 붙여 넣는다.
- 사용자 리뷰 요청으로 명령을 끝까지 실행하지 못했다면 `사용자 리뷰 요청`에 실행한 명령, 실제 출력, 미실행 명령의 사유를 기록한다.
- mobile/UI hang, timeout, 또는 2분 무진행은 blind retry를 중단하고 focused rerun 명령과 screenshot/window/UI-tree evidence path를 남기며, 불가능하면 정확한 사유를 남긴다.
### CHROME-TESTS-1 중간 검증
```
$ cd packages/messaging_flutter && flutter test test/nexo_messaging_vm_test.dart
00:00 +0: loading /config/workspace/nexo/packages/messaging_flutter/test/nexo_messaging_vm_test.dart
00:00 +0: NexoMessagingPlugin web notification permission on VM reports unsupported status on non-web platforms
00:00 +1: NexoMessagingPlugin web notification permission on VM request is a no-op unsupported status on non-web platforms
00:00 +2: All tests passed!
```
### CHROME-TESTS-2 중간 검증
```
$ cd packages/messaging_flutter && flutter test --platform chrome test/nexo_messaging_web_test.dart
00:00 +0: loading /config/workspace/nexo/packages/messaging_flutter/test/nexo_messaging_web_test.dart
00:00 +0 -1: loading /config/workspace/nexo/packages/messaging_flutter/test/nexo_messaging_web_test.dart [E]
Failed to load "/config/workspace/nexo/packages/messaging_flutter/test/nexo_messaging_web_test.dart":
Failed to find "google-chrome" in the search path.
Command: google-chrome
(local Chrome 없음 — cloud runner에서 재실행 필요)
$ command -v google-chrome
not found
$ command -v chromium
not found
$ command -v chrome
not found
```
### 최종 검증
```
$ cd packages/messaging_flutter && flutter test
00:00 +0: loading /config/workspace/nexo/packages/messaging_flutter/test/nexo_messaging_test.dart
[... 44 tests ...]
00:00 +44: All tests passed!
$ bash -n bin/test
exit=0
$ bin/test
[... 44 VM tests passed ...]
skip packages/messaging_flutter Chrome tests: set NEXO_FLUTTER_WEB_TEST=1 to run Flutter web tests
[... apps/flutter-test 10 tests passed ...]
skip services/core/server: set NEXO_CORE_GO_TEST=1 to run the full Go test suite
$ NEXO_FLUTTER_WEB_TEST=1 bin/test
[... 44 VM tests passed ...]
Failed to find "google-chrome" in the search path.
(VM 통과, Chrome launch 실패 — local Chrome 없음. cloud runner에서 재실행 필요)
```
### 리뷰 재검증
```
$ cd packages/messaging_flutter && CHROME_EXECUTABLE=/config/.cache/ms-playwright/chromium-1178/chrome-linux/chrome flutter test --platform chrome test/nexo_messaging_web_test.dart
00:00 +0: loading /config/workspace/nexo/packages/messaging_flutter/test/nexo_messaging_web_test.dart
00:00 +0: browser Notification API is visible in Chrome runtime
00:00 +1: plugin reports browser permission status in Chrome runtime
00:00 +2: All tests passed!
$ CHROME_EXECUTABLE=/config/.cache/ms-playwright/chromium-1178/chrome-linux/chrome NEXO_FLUTTER_WEB_TEST=1 bin/test
[... packages/messaging_flutter VM tests passed ...]
00:00 +0: loading /config/workspace/nexo/packages/messaging_flutter/test/nexo_messaging_web_test.dart
00:00 +0: test/nexo_messaging_web_test.dart: browser Notification API is visible in Chrome runtime
00:00 +1: test/nexo_messaging_web_test.dart: plugin reports browser permission status in Chrome runtime
[... packages/messaging_flutter Chrome suite passed ...]
[... apps/flutter-test 10 tests passed ...]
skip services/core/server: set NEXO_CORE_GO_TEST=1 to run the full Go test suite
$ cd packages/messaging_flutter && flutter analyze --no-fatal-infos
Analyzing messaging_flutter...
No issues found! (ran in 4.3s)
```
---
> **[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.
## 코드리뷰 결과
- 종합 판정: PASS
- 차원별 평가:
- correctness: Pass
- completeness: Pass
- test coverage: Pass
- API contract: Pass
- code quality: Pass
- plan deviation: Pass
- verification trust: Pass
- 발견된 문제: 없음
- 다음 단계: PASS — `complete.log` 작성 후 task directory를 `agent-task/archive/2026/06/m-flutter-web-notification-smoke/03_chrome_tests/`로 이동한다. `m-flutter-web-notification-smoke` 완료 이벤트 메타데이터를 보고하며, roadmap 수정은 code-review에서 수행하지 않는다.

View file

@ -0,0 +1,47 @@
# Complete - m-flutter-web-notification-smoke/03_chrome_tests
## 완료 일시
2026-06-08
## 요약
Chrome/web notification test separation task completed in 1 review loop with final verdict PASS.
## 루프 이력
| Plan | Review | Verdict | 메모 |
|------|--------|---------|------|
| `plan_cloud_G07_0.log` | `code_review_cloud_G07_0.log` | PASS | VM-only unsupported assertions were split, browser Notification support tests were added, and Chrome opt-in verification passed with `CHROME_EXECUTABLE`. |
## 구현/정리 내용
- Moved non-web browser notification permission assertions into `packages/messaging_flutter/test/nexo_messaging_vm_test.dart` with `@TestOn('vm')`.
- Added `packages/messaging_flutter/test/nexo_messaging_web_test.dart` with `@TestOn('browser')` to verify Chrome runtime Notification API support and plugin permission status without prompting.
- Kept shared `packages/messaging_flutter/test/nexo_messaging_test.dart` platform-neutral for browser permission expectations.
- Verified the root `bin/test` opt-in Chrome route with `NEXO_FLUTTER_WEB_TEST=1` and documented the helper flag in `README.md`.
## 최종 검증
- `cd packages/messaging_flutter && flutter test test/nexo_messaging_vm_test.dart` - PASS; `00:00 +2: All tests passed!`
- `cd packages/messaging_flutter && flutter test` - PASS; `00:00 +44: All tests passed!`
- `cd packages/messaging_flutter && CHROME_EXECUTABLE=/config/.cache/ms-playwright/chromium-1178/chrome-linux/chrome flutter test --platform chrome test/nexo_messaging_web_test.dart` - PASS; `00:00 +2: All tests passed!`
- `bash -n bin/test` - PASS; `bash-n-exit=0`
- `bin/test` - PASS; package VM tests and `apps/flutter-test` tests passed, Chrome route emitted the expected opt-in skip message, and core Go tests were skipped by flag.
- `CHROME_EXECUTABLE=/config/.cache/ms-playwright/chromium-1178/chrome-linux/chrome NEXO_FLUTTER_WEB_TEST=1 bin/test` - PASS; package VM tests, package Chrome tests, and `apps/flutter-test` tests passed, while optional core Go tests were skipped by flag.
- `cd packages/messaging_flutter && flutter analyze --no-fatal-infos` - PASS; `No issues found!`
## Roadmap Completion
- Milestone: `agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md`
- Completed task ids:
- `chrome-tests`: PASS; evidence=`agent-task/archive/2026/06/m-flutter-web-notification-smoke/03_chrome_tests/plan_cloud_G07_0.log`, `agent-task/archive/2026/06/m-flutter-web-notification-smoke/03_chrome_tests/code_review_cloud_G07_0.log`; verification=`CHROME_EXECUTABLE=/config/.cache/ms-playwright/chromium-1178/chrome-linux/chrome NEXO_FLUTTER_WEB_TEST=1 bin/test`
- Not completed task ids: 없음
## 잔여 Nit
- 없음
## 후속 작업
- 없음

View file

@ -0,0 +1,257 @@
<!-- task=m-flutter-web-notification-smoke/03_chrome_tests plan=0 tag=CHROME-TESTS -->
# Implementation Plan - CHROME-TESTS
## 이 파일을 읽는 구현 에이전트에게
`CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채우는 것이 필수다. 구현 후 검증을 실행하고 실제 출력과 변경 내용을 채운 뒤 active 파일을 그대로 두고 리뷰 준비를 보고한다. 사용자 결정, 사용자 소유 외부 환경, scope 충돌 때문에 막히면 review stub의 `사용자 리뷰 요청` 섹션에 근거를 쓰고 멈춘다. 구현 중 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 최종 archive, `complete.log`, roadmap 반영은 code-review/runtime 책임이다.
## Roadmap Targets
- Milestone: `agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md`
- Task ids:
- `chrome-tests`: `packages/messaging_flutter`의 Chrome/web 테스트가 web runtime에서는 browser notification support를 기대하고, VM 테스트는 non-web unsupported를 기대하도록 분리한다.
- Completion mode: check-on-pass
## 분석 결과
### 읽은 파일
- `agent-roadmap/current.md`
- `agent-roadmap/phase/messaging-runtime/PHASE.md`
- `agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md`
- `agent-ops/rules/project/domain/messaging-flutter/rules.md`
- `agent-ops/rules/project/domain/workspace-ops/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/messaging-flutter-smoke.md`
- `agent-test/local/workspace-ops-smoke.md`
- `bin/test`
- `README.md`
- `packages/messaging_flutter/pubspec.yaml`
- `packages/messaging_flutter/lib/src/nexo_messaging_plugin.dart`
- `packages/messaging_flutter/lib/src/web/browser_notification_interop.dart`
- `packages/messaging_flutter/lib/src/web/browser_notification_interop_web.dart`
- `packages/messaging_flutter/lib/src/web/web_notification_permission_client_stub.dart`
- `packages/messaging_flutter/lib/src/web/web_notification_permission_client_web.dart`
- `packages/messaging_flutter/lib/src/web_notification_permission_client_factory.dart`
- `packages/messaging_flutter/test/nexo_messaging_test.dart`
### 테스트 환경 규칙
- test_env: local.
- `agent-test/local/rules.md`를 읽었다.
- matched profiles: `agent-test/local/messaging-flutter-smoke.md`, `agent-test/local/workspace-ops-smoke.md`.
- 적용 명령: `cd packages/messaging_flutter && flutter test`, `cd packages/messaging_flutter && flutter test --platform chrome`, `bin/test`, `bash -n bin/test`, `rg --sort path`.
- 현재 local checkout에는 `google-chrome`, `chromium`, `chrome` 실행 파일이 PATH에 없어 `flutter test --platform chrome`가 Chrome launch 전에 실패했다. 실제 Chrome PASS evidence는 Chrome 사용 가능 환경 또는 standard remote runner에서 확보해야 한다.
- `bin/test`에는 `NEXO_FLUTTER_WEB_TEST=1` opt-in route가 있으므로 기본 `bin/test`는 Chrome 검증 skip 사유를 출력한다.
### 테스트 커버리지 공백
- `packages/messaging_flutter/test/nexo_messaging_test.dart:382`의 web permission tests는 non-web unsupported 기대값을 단일 shared test file에 둔다. Chrome에서 같은 파일을 실행하면 browser Notification API 기대값과 충돌한다.
- `packages/messaging_flutter/test/nexo_messaging_test.dart:596`의 foreground display/click tests는 fake interop만 검증한다. 실제 `BrowserNotificationInteropImpl`가 Chrome runtime에서 support를 보고하는지 확인하는 browser test가 없다.
- `bin/test:9`의 opt-in route는 추가됐지만, 현재 test suite가 Chrome에서 통과하도록 파일/expectation 분리가 아직 되어 있지 않다.
### 심볼 참조
- Renamed/removed symbols: none.
### 분할 판단
- Split policy evaluated.
- 공유 task group: `agent-task/m-flutter-web-notification-smoke`.
- `03_chrome_tests`: Chrome/web test separation. No runtime predecessor encoded in the directory name; prior `01_web_scaffold` and `02+01_web_runtime` are already archived, and `helper-route` was handled directly before this plan.
- `04+03_manual_evidence_closeout`: depends on `03_chrome_tests` complete.log before closeout evidence can be finalized.
- 분리 이유: Chrome test separation changes package tests and browser expectations, while manual evidence closeout is roadmap/evidence assembly and should not be mixed with browser test implementation.
### 범위 결정 근거
- 포함: `packages/messaging_flutter/test/**`, 필요 시 browser notification test-only seams in `packages/messaging_flutter/lib/src/**`, `bin/test` opt-in verification.
- 제외: Full Web Push, service worker, VAPID, server device-token registration, core/push-proxy web target, `apps/flutter-test` runtime UI changes.
- Chrome executable installation is environment setup, not repository implementation.
### 빌드 등급
- Build lane/grade: `cloud-G07`. Chrome/web runtime expectation, local Chrome absence, and cross-platform test separation need browser-aware evidence recovery.
## 구현 체크리스트
- [ ] VM-only unsupported web permission assertions are isolated so `flutter test` still proves non-web unsupported behavior.
- [ ] Chrome/web tests are added so browser Notification support/current permission behavior is verified without prompting the user.
- [ ] `NEXO_FLUTTER_WEB_TEST=1 bin/test` or `flutter test --platform chrome` is run in a Chrome-capable environment and records real stdout/stderr.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
### [CHROME-TESTS-1] VM-only permission tests 분리
#### 문제
`packages/messaging_flutter/test/nexo_messaging_test.dart:382` and `:394` assert unsupported browser notification permission behavior for non-web platforms inside the shared test file. The milestone requires Chrome/web tests to expect browser support separately.
#### 해결 방법
Move the non-web unsupported permission tests into a VM-only test file and keep shared tests platform-neutral.
Before:
```dart
// packages/messaging_flutter/test/nexo_messaging_test.dart:375
group('NexoMessagingPlugin web notification permission', () {
...
test('reports unsupported status on non-web platforms', () async {
```
After:
```dart
// packages/messaging_flutter/test/nexo_messaging_vm_test.dart
@TestOn('vm')
library;
import 'package:flutter_test/flutter_test.dart';
import 'package:nexo_messaging/nexo_messaging.dart';
void main() {
group('NexoMessagingPlugin web notification permission on VM', () {
...
});
}
```
#### 수정 파일 및 체크리스트
- [ ] `packages/messaging_flutter/test/nexo_messaging_test.dart`
- [ ] `packages/messaging_flutter/test/nexo_messaging_vm_test.dart`
#### 테스트 작성
Write/keep VM regression tests:
- file: `packages/messaging_flutter/test/nexo_messaging_vm_test.dart`
- assertions: `getWebNotificationPermissionStatus()` and `requestWebNotificationPermission()` return unsupported on VM.
#### 중간 검증
```sh
cd packages/messaging_flutter && flutter test test/nexo_messaging_vm_test.dart
```
Expected: VM-only unsupported tests pass.
### [CHROME-TESTS-2] Chrome/browser tests 추가
#### 문제
`packages/messaging_flutter/test/nexo_messaging_test.dart:596` verifies foreground display and click routing through a fake interop, but no Chrome test proves the web implementation sees browser Notification support. `packages/messaging_flutter/lib/src/nexo_messaging_plugin.dart:51` creates the web permission client through a conditional factory, so a browser test should verify the web branch.
#### 해결 방법
Add a browser-only test file that imports web-safe APIs and avoids permission prompts. Test current status/support and keep user-prompting `requestPermission()` out of automated Chrome tests.
Before:
```dart
// packages/messaging_flutter/test/nexo_messaging_test.dart:596
group('showWebForegroundNotification fake interop', () {
```
After:
```dart
// packages/messaging_flutter/test/nexo_messaging_web_test.dart
@TestOn('browser')
library;
import 'package:flutter_test/flutter_test.dart';
import 'package:nexo_messaging/nexo_messaging.dart';
import 'package:nexo_messaging/src/web/browser_notification_interop_web.dart';
void main() {
test('browser Notification API is visible in Chrome runtime', () {
expect(BrowserNotificationInteropImpl().isSupported, isTrue);
});
test('plugin reports browser permission status in Chrome runtime', () async {
final status = await NexoMessagingPlugin.instance
.getWebNotificationPermissionStatus();
expect(status.isSupported, isTrue);
expect(status.rawPermission, isNotNull);
});
}
```
#### 수정 파일 및 체크리스트
- [ ] `packages/messaging_flutter/test/nexo_messaging_web_test.dart`
- [ ] If needed, `packages/messaging_flutter/lib/src/nexo_messaging_plugin.dart` test-only seams only; do not change public API unless a failing Chrome test proves it necessary.
#### 테스트 작성
Write Chrome tests:
- file: `packages/messaging_flutter/test/nexo_messaging_web_test.dart`
- assertions: browser `Notification` interop is supported in Chrome; plugin current permission status reports supported without opening a prompt.
#### 중간 검증
```sh
cd packages/messaging_flutter && flutter test --platform chrome test/nexo_messaging_web_test.dart
```
Expected: Chrome browser tests pass in a Chrome-capable environment.
### [CHROME-TESTS-3] Opt-in route 전체 검증
#### 문제
`bin/test:9` now exposes `NEXO_FLUTTER_WEB_TEST=1`, but the milestone Task is not complete until the package Chrome suite can pass and default `bin/test` clearly reports skipped web validation when the flag is absent.
#### 해결 방법
Run both default and opt-in routes. If the local environment lacks Chrome, use the standard remote runner or another Chrome-capable environment and record the exact command/output. Do not mark this task complete with only a local "chrome missing" failure.
#### 수정 파일 및 체크리스트
- [ ] `bin/test` only if route needs adjustment after test split.
- [ ] `README.md` only if the command contract changes.
- [ ] `agent-test/local/messaging-flutter-smoke.md` only if the local rule needs wording correction.
#### 테스트 작성
No additional test file for `bin/test`; shell/helper behavior is verified with direct command output.
#### 중간 검증
```sh
bash -n bin/test
bin/test
NEXO_FLUTTER_WEB_TEST=1 bin/test
```
Expected:
- `bash -n bin/test` exits 0.
- default `bin/test` exits 0 and includes the Chrome skip message.
- `NEXO_FLUTTER_WEB_TEST=1 bin/test` exits 0 in a Chrome-capable environment.
## 수정 파일 요약
| 파일 | 항목 |
| --- | --- |
| `packages/messaging_flutter/test/nexo_messaging_test.dart` | CHROME-TESTS-1 |
| `packages/messaging_flutter/test/nexo_messaging_vm_test.dart` | CHROME-TESTS-1 |
| `packages/messaging_flutter/test/nexo_messaging_web_test.dart` | CHROME-TESTS-2 |
| `packages/messaging_flutter/lib/src/nexo_messaging_plugin.dart` | CHROME-TESTS-2 only if required by failing Chrome evidence |
| `bin/test` | CHROME-TESTS-3 only if route adjustment is required |
| `README.md` | CHROME-TESTS-3 only if command contract changes |
| `agent-test/local/messaging-flutter-smoke.md` | CHROME-TESTS-3 only if command contract changes |
## 최종 검증
```sh
cd packages/messaging_flutter && flutter test
cd packages/messaging_flutter && flutter test test/nexo_messaging_vm_test.dart
cd packages/messaging_flutter && flutter test --platform chrome test/nexo_messaging_web_test.dart
bash -n bin/test
bin/test
NEXO_FLUTTER_WEB_TEST=1 bin/test
```
Expected: VM tests pass, Chrome/web tests pass in a Chrome-capable environment, default helper reports Chrome skip when opt-in is absent, opt-in helper exits 0 when Chrome is available. If local Chrome is missing, record `command -v google-chrome`, `command -v chromium`, and `command -v chrome` output and use a Chrome-capable runner instead of closing the task as PASS.
모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.

View file

@ -0,0 +1,171 @@
<!-- task=m-flutter-web-notification-smoke/04+03_manual_evidence_closeout plan=0 tag=MANUAL-EVIDENCE -->
# Code Review Reference - MANUAL-EVIDENCE
> **[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, user-owned 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`. Evidence gaps that a follow-up agent can close by rerunning commands or collecting artifacts are normal follow-up issues, not user-review blockers by themselves.
> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation; record the needed decision in `사용자 리뷰 요청` and stop for code-review.
> 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-06-08
task=m-flutter-web-notification-smoke/04+03_manual_evidence_closeout, plan=0, tag=MANUAL-EVIDENCE
## Roadmap Targets
- Milestone: `agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md`
- Task ids:
- `manual-evidence`: browser notification permission/display/click 수동 smoke evidence 기준을 민감값 없이 정리한다.
- Completion mode: check-on-pass
## 이 파일을 읽는 리뷰 에이전트에게
> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.
각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다.
1. 판정을 append한다.
2. `CODE_REVIEW-local-G05.md` → `code_review_local_G05_N.log`, `PLAN-local-G05.md` → `plan_local_G05_M.log`로 아카이브한다.
3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-flutter-web-notification-smoke/04+03_manual_evidence_closeout/`로 이동한다. WARN/FAIL이면 user-review gate를 확인한 뒤 다음 active plan/review 파일 또는 `USER_REVIEW.md`를 작성한다.
4. PASS이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.
---
## 구현 항목별 완료 여부
| 항목 | 완료 여부 |
|------|---------|
| [MANUAL-EVIDENCE-1] Predecessor gate | [x] |
| [MANUAL-EVIDENCE-2] Evidence matrix 확인 | [x] |
## 구현 체크리스트
- [x] `03_chrome_tests` predecessor complete log를 확인한다.
- [x] `web-scaffold`, `web-runtime`, `helper-route`, `chrome-tests` evidence를 민감값 없이 요약한다.
- [x] Full Web Push, service worker, VAPID, core/push-proxy web target이 scope-excluded로 남아 있음을 확인한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
## 코드리뷰 전용 체크리스트
> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다.
- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [x] active `CODE_REVIEW-*-G??.md`를 `code_review_local_G05_N.log`로 아카이브한다.
- [x] active `PLAN-*-G??.md`를 `plan_local_G05_M.log`로 아카이브한다.
- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다.
- [x] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [x] PASS이면 active task 디렉터리 `agent-task/{task_name}/`를 `agent-task/archive/YYYY/MM/{task_name}/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [x] PASS이고 task group이 `m-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [x] PASS split 작업이면 이동 후 빈 active parent `agent-task/{task_group}/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-{build_lane}-GNN.md`와 `CODE_REVIEW-{review_lane}-GNN.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로 이동한다.
## 계획 대비 변경 사항
_구현 에이전트가 계획과 다르게 구현한 부분을 이유와 함께 기록한다._
없음
## 주요 설계 결정
_구현 에이전트가 주요 설계 결정 사항을 기록한다._
없음 (`manual-evidence`는 증거 집계 Task로 source 변경 없음)
## 사용자 리뷰 요청
_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 구현 에이전트는 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._
- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음
## 리뷰어를 위한 체크포인트
- `03_chrome_tests` complete log must exist before this task can PASS.
- Evidence must include remote web runtime, user browser click action, Chrome/web test split, helper opt-in route, and Full Web Push exclusion.
- Raw host, forwarded URL, credential, token, and secret values must not appear in tracked evidence.
## 검증 결과
_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._
필수 규칙:
- 검증 명령은 고정된 계약이다. 임의로 대체하지 않는다.
- 대체가 필요하면 `계획 대비 변경 사항`에 이유와 대체 명령을 기록한다.
- `검증 결과`에는 실제 stdout/stderr를 붙여 넣는다.
- 사용자 리뷰 요청으로 명령을 끝까지 실행하지 못했다면 `사용자 리뷰 요청`에 실행한 명령, 실제 출력, 미실행 명령의 사유를 기록한다.
- mobile/UI hang, timeout, 또는 2분 무진행은 blind retry를 중단하고 focused rerun 명령과 screenshot/window/UI-tree evidence path를 남기며, 불가능하면 정확한 사유를 남긴다.
### MANUAL-EVIDENCE-1 중간 검증
```
$ find agent-task/m-flutter-web-notification-smoke -maxdepth 2 -path '*/03_chrome_tests/complete.log' -print
$ find agent-task/archive -path '*/m-flutter-web-notification-smoke/03_chrome_tests/complete.log' -print
agent-task/archive/2026/06/m-flutter-web-notification-smoke/03_chrome_tests/complete.log
```
### 최종 검증
```
$ find agent-task/m-flutter-web-notification-smoke -maxdepth 2 -path '*/03_chrome_tests/complete.log' -print
# no result
$ find agent-task/archive -path '*/m-flutter-web-notification-smoke/03_chrome_tests/complete.log' -print
agent-task/archive/2026/06/m-flutter-web-notification-smoke/03_chrome_tests/complete.log
$ rg --sort path -n "web-scaffold|web-runtime|helper-route|chrome-tests|manual-evidence|Full Web Push|service worker|VAPID" agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md
agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md:39:- [x] [web-scaffold] `apps/flutter-test`에 Flutter Web scaffold를 추가하고 web build가 통과하도록 구성한다. 검증: 원격 runner에서 `apps/flutter-test` web build가 성공해야 한다.
agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md:40:- [x] [web-runtime] 원격 Flutter Web server와 forwarded localhost URL 기반 수동 smoke 절차를 정리한다. 검증: 사용자가 forwarded URL에서 permission 요청, notification display, click/open routing 상태를 확인할 수 있어야 한다.
agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md:46:- [ ] [chrome-tests] `packages/messaging_flutter`의 Chrome/web 테스트가 web runtime에서는 browser notification support를 기대하고, VM 테스트는 non-web unsupported를 기대하도록 분리한다. 검증: 원격 runner에서 package Chrome 테스트가 통과해야 한다.
agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md:47:- [x] [helper-route] workspace helper 또는 테스트 규칙에 web build/smoke opt-in 경로를 추가해 `bin/test`만으로 web smoke가 완료된 것처럼 보이지 않게 한다. 검증: web 검증을 생략한 경우 skip 또는 미실행 사유가 명확히 보고되어야 한다.
agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md:53:- [ ] [manual-evidence] browser notification permission/display/click 수동 smoke evidence 기준을 민감값 없이 정리한다. 검증: 완료 리뷰에 원격 실행 명령, 사용자 확인 결과, 생략된 Full Web Push 범위가 함께 남아야 한다.
agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md:67:- 브라우저가 닫힌 상태에서도 수신되는 Full Web Push 구현
agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md:68:- service worker, VAPID, `web_rn-v2` server device-token 등록, core/push-proxy web target 구현
agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md:78:- 확인 필요: `web-scaffold`, `web-runtime`, `helper-route` evidence는 완료됐다. 남은 확인은 Chrome/web test 분리와 수동 evidence 기준 closeout이다.
$ rg --sort path -n "NEXO_FLUTTER_WEB_TEST|flutter test --platform chrome|Chrome tests" README.md bin/test
README.md:79:| Flutter Web/Chrome 테스트 포함 | `NEXO_FLUTTER_WEB_TEST=1 bin/test` | `packages/messaging_flutter`에서 `flutter test --platform chrome`을 실행한다. Flutter Chrome test 환경이 필요하다. |
README.md:157:| `NEXO_FLUTTER_WEB_TEST` | `bin/test`에서 `packages/messaging_flutter` Chrome/web 테스트를 실행한다. | `0` |
bin/test:9: if [ "${NEXO_FLUTTER_WEB_TEST:-0}" = "1" ]; then
bin/test:10: (cd "$root/packages/messaging_flutter" && flutter test --platform chrome)
bin/test:12: echo "skip packages/messaging_flutter Chrome tests: set NEXO_FLUTTER_WEB_TEST=1 to run Flutter web tests"
```
### MANUAL-EVIDENCE-2 정합성 점검
- 01/02/03 선행 complete log는 모두 archive 경로에서 확인되어 증빙 체인이 종료됨.
- Full Web Push/service worker/VAPID/core-push-proxy web target은 milestone의 범위 제외 항목으로 남아, 해당 항목은 closeout의 검증 범위에서 제외됨.
- 사용자 browser smoke 확인(권한, 표시, 클릭/open)은 `02+01_web_runtime` complete log에 `USER_REVIEW.md` 처리로 확정됨.
- helper-route: `bin/test`의 `NEXO_FLUTTER_WEB_TEST` skip/opt-in contract + `apps/flutter-test/README.md` remote preview flow가 보완됨.
---
> **[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.
## 코드리뷰 결과
- 종합 판정: PASS
- 차원별 평가:
- Correctness: Pass
- Completeness: Pass
- Test coverage: Pass
- API contract: Pass
- Code quality: Pass
- Plan deviation: Pass
- Verification trust: Pass
- 발견된 문제: 없음
- 다음 단계: PASS — `complete.log` 작성 후 task directory를 `agent-task/archive/2026/06/m-flutter-web-notification-smoke/04+03_manual_evidence_closeout/`로 이동한다. `m-flutter-web-notification-smoke` 완료 이벤트 메타데이터를 보고하며, roadmap 수정은 code-review에서 수행하지 않는다.

View file

@ -0,0 +1,44 @@
# Complete - m-flutter-web-notification-smoke/04+03_manual_evidence_closeout
## 완료 일시
2026-06-08
## 요약
Manual evidence closeout을 1회 리뷰했고 최종 판정은 PASS다.
## 루프 이력
| Plan | Review | Verdict | 메모 |
|------|--------|---------|------|
| `plan_local_G05_0.log` | `code_review_local_G05_0.log` | PASS | `03_chrome_tests` predecessor complete log, browser smoke user evidence, helper opt-in route, and Full Web Push exclusion evidence were all confirmed without recording raw environment values. |
## 구현/정리 내용
- `01_web_scaffold`, `02+01_web_runtime`, and `03_chrome_tests` complete logs exist under the same milestone task archive and provide the required evidence chain.
- Browser notification permission/display/click evidence is covered by the resolved `02+01_web_runtime` user-review PASS.
- `bin/test` documents and emits the `NEXO_FLUTTER_WEB_TEST=1` Chrome opt-in route, while the default path reports Chrome/web tests as skipped rather than silently completed.
- Full Web Push, service worker, VAPID, and core/push-proxy web target work remain explicitly outside this milestone's scope.
## 최종 검증
- `find agent-task/m-flutter-web-notification-smoke -maxdepth 2 -path '*/03_chrome_tests/complete.log' -print` - PASS; no active predecessor complete log remained.
- `find agent-task/archive -path '*/m-flutter-web-notification-smoke/03_chrome_tests/complete.log' -print` - PASS; exactly one archived `03_chrome_tests/complete.log` was found.
- `rg --sort path -n "web-scaffold|web-runtime|helper-route|chrome-tests|manual-evidence|Full Web Push|service worker|VAPID" agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md` - PASS; completed evidence, pending manual closeout, and scope-excluded Full Web Push boundaries were visible.
- `rg --sort path -n "NEXO_FLUTTER_WEB_TEST|flutter test --platform chrome|Chrome tests" README.md bin/test` - PASS; the root helper opt-in route and README flag documentation were present.
## Roadmap Completion
- Milestone: `agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md`
- Completed task ids:
- `manual-evidence`: PASS; evidence=`agent-task/archive/2026/06/m-flutter-web-notification-smoke/04+03_manual_evidence_closeout/plan_local_G05_0.log`, `agent-task/archive/2026/06/m-flutter-web-notification-smoke/04+03_manual_evidence_closeout/code_review_local_G05_0.log`; verification=`find` predecessor gate and `rg` evidence/scope checks recorded in `code_review_local_G05_0.log`
- Not completed task ids: 없음
## 잔여 Nit
- 없음
## 후속 작업
- 없음

View file

@ -0,0 +1,165 @@
<!-- task=m-flutter-web-notification-smoke/04+03_manual_evidence_closeout plan=0 tag=MANUAL-EVIDENCE -->
# Implementation Plan - MANUAL-EVIDENCE
## 이 파일을 읽는 구현 에이전트에게
`CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채우는 것이 필수다. 이 작업은 evidence closeout 전용이다. `03_chrome_tests` 완료 전에는 구현하지 말고 dependency missing으로 기록한다. 구현 중 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 최종 archive, `complete.log`, roadmap 반영은 code-review/runtime 책임이다.
## Roadmap Targets
- Milestone: `agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md`
- Task ids:
- `manual-evidence`: browser notification permission/display/click 수동 smoke evidence 기준을 민감값 없이 정리한다.
- Completion mode: check-on-pass
## 분석 결과
### 읽은 파일
- `agent-roadmap/current.md`
- `agent-roadmap/phase/messaging-runtime/PHASE.md`
- `agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md`
- `agent-task/archive/2026/06/m-flutter-web-notification-smoke/01_web_scaffold/complete.log`
- `agent-task/archive/2026/06/m-flutter-web-notification-smoke/02+01_web_runtime/complete.log`
- `agent-ops/rules/project/domain/workspace-ops/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/messaging-flutter-smoke.md`
- `agent-test/local/runtime-env.md`
- `README.md`
- `bin/test`
### 테스트 환경 규칙
- test_env: local.
- `agent-test/local/rules.md`를 읽었다.
- matched profiles: `agent-test/local/messaging-flutter-smoke.md`, `agent-test/local/runtime-env.md`, `agent-test/local/workspace-ops-smoke.md`.
- evidence closeout은 새 product code를 만들지 않는다. 검증은 완료 로그, roadmap task 상태, `bin/test` skip/opt-in 계약, Full Web Push 범위 제외 기록을 대조한다.
### 테스트 커버리지 공백
- `manual-evidence`는 테스트 파일 추가 대상이 아니라 evidence assembly Task다.
- `chrome-tests`가 완료되기 전에는 final evidence가 불완전하므로 이 plan은 `03_chrome_tests` complete log를 hard dependency로 둔다.
### 심볼 참조
- Renamed/removed symbols: none.
### 분할 판단
- Split policy evaluated.
- This plan is `04+03_manual_evidence_closeout`, dependent on sibling index `03_chrome_tests`.
- Required predecessor: `agent-task/m-flutter-web-notification-smoke/03_chrome_tests/complete.log` or archived `agent-task/archive/*/*/m-flutter-web-notification-smoke/03_chrome_tests/complete.log`.
- Current state at plan creation: predecessor `03_chrome_tests` is not complete, so implementation must wait for runtime dependency satisfaction.
- The closeout is separated from Chrome test implementation because it only assembles completion evidence and should not modify browser test behavior.
### 범위 결정 근거
- 포함: milestone evidence review readiness, existing completed task logs, Full Web Push exclusion statement, user browser smoke evidence, Chrome test completion evidence.
- 제외: new Chrome tests, helper route implementation, Full Web Push/service worker/VAPID/core/push-proxy work, archive movement of the milestone.
- This plan must not mark the Milestone `[완료]` or archive it; user approval and archive are separate roadmap actions.
### 빌드 등급
- Build lane/grade: `local-G05`. The task is deterministic evidence assembly with one dependency gate and no source behavior change.
## 의존 관계 및 구현 순서
1. Confirm `03_chrome_tests` complete log exists under active or archive path.
2. Read only the required same task group complete logs for `01_web_scaffold`, `02+01_web_runtime`, and `03_chrome_tests`.
3. Confirm the milestone still excludes Full Web Push and has all implementation evidence needed for `[검토중]`.
4. Fill this review stub with exact evidence and stop for code review.
## 구현 체크리스트
- [ ] `03_chrome_tests` predecessor complete log를 확인한다.
- [ ] `web-scaffold`, `web-runtime`, `helper-route`, `chrome-tests` evidence를 민감값 없이 요약한다.
- [ ] Full Web Push, service worker, VAPID, core/push-proxy web target이 scope-excluded로 남아 있음을 확인한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
### [MANUAL-EVIDENCE-1] Predecessor gate
#### 문제
`manual-evidence`는 final closeout Task이므로 `03_chrome_tests`가 완료되기 전에는 완료 리뷰 근거가 불완전하다.
#### 해결 방법
Check the sibling dependency from the directory name:
```sh
find agent-task/m-flutter-web-notification-smoke -maxdepth 2 -path '*/03_chrome_tests/complete.log' -print
find agent-task/archive -path '*/m-flutter-web-notification-smoke/03_chrome_tests/complete.log' -print
```
Expected: exactly one `03_chrome_tests/complete.log`.
#### 수정 파일 및 체크리스트
- [ ] 이 항목은 repository source file 수정 없음.
#### 테스트 작성
No test file. This is a task protocol dependency check.
#### 중간 검증
```sh
find agent-task/m-flutter-web-notification-smoke -maxdepth 2 -path '*/03_chrome_tests/complete.log' -print
find agent-task/archive -path '*/m-flutter-web-notification-smoke/03_chrome_tests/complete.log' -print
```
Expected: exactly one predecessor complete log.
### [MANUAL-EVIDENCE-2] Evidence matrix 확인
#### 문제
`agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md:53` requires manual evidence to include remote commands, user confirmation, and Full Web Push exclusion. The final closeout must not rely only on fake interop tests.
#### 해결 방법
Collect evidence from complete logs and current docs without copying raw host/URL/secret values:
- `01_web_scaffold`: web scaffold and build evidence.
- `02+01_web_runtime`: remote build, forwarded preview reachability, user browser permission/display/click action evidence.
- `03_chrome_tests`: VM/Chrome split and Chrome test evidence.
- `helper-route`: `bin/test` default skip and `NEXO_FLUTTER_WEB_TEST=1` opt-in route.
- Scope exclusion: Full Web Push/service worker/VAPID/core/push-proxy web target remain outside this milestone.
#### 수정 파일 및 체크리스트
- [ ] `CODE_REVIEW-local-G05.md` evidence sections only.
- [ ] Do not edit `agent-roadmap/**` directly for final state; runtime/update-roadmap owns milestone Task check and `[검토중]` transition after PASS.
#### 테스트 작성
No test file. This task verifies completion evidence.
#### 중간 검증
```sh
rg --sort path -n "web-scaffold|web-runtime|helper-route|chrome-tests|manual-evidence|Full Web Push|service worker|VAPID" agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md
rg --sort path -n "NEXO_FLUTTER_WEB_TEST|flutter test --platform chrome|Chrome tests" README.md bin/test
```
Expected: completed and remaining evidence boundaries are visible without raw environment values.
## 수정 파일 요약
| 파일 | 항목 |
| --- | --- |
| `agent-task/m-flutter-web-notification-smoke/04+03_manual_evidence_closeout/CODE_REVIEW-local-G05.md` | MANUAL-EVIDENCE-1, MANUAL-EVIDENCE-2 |
## 최종 검증
```sh
find agent-task/m-flutter-web-notification-smoke -maxdepth 2 -path '*/03_chrome_tests/complete.log' -print
find agent-task/archive -path '*/m-flutter-web-notification-smoke/03_chrome_tests/complete.log' -print
rg --sort path -n "web-scaffold|web-runtime|helper-route|chrome-tests|manual-evidence|Full Web Push|service worker|VAPID" agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md
rg --sort path -n "NEXO_FLUTTER_WEB_TEST|flutter test --platform chrome|Chrome tests" README.md bin/test
```
Expected: predecessor `03_chrome_tests` is complete; evidence covers remote build, forwarded browser confirmation, Chrome test separation, helper opt-in route, and explicit Full Web Push exclusion. Raw environment values are absent.
모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.

View file

@ -1,90 +0,0 @@
<!-- task=m-flutter-web-notification-smoke/02+01_web_runtime plan=0 tag=WEB-RUNTIME -->
# Code Review Reference - WEB-RUNTIME
> **[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, user-owned 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`.
> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only.
## 개요
date=2026-06-08
task=m-flutter-web-notification-smoke/02+01_web_runtime, plan=0, tag=WEB-RUNTIME
## Roadmap Targets
- Milestone: `agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md`
- Task ids:
- `web-runtime`: 원격 Flutter Web server와 forwarded localhost URL 기반 수동 smoke 절차를 정리한다.
- Completion mode: check-on-pass
## 이 파일을 읽는 리뷰 에이전트에게
> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.
각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요. PASS이고 task group이 `m-<milestone-slug>`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
---
## 구현 항목별 완료 여부
| 항목 | 완료 여부 |
|------|---------|
| [WEB-RUNTIME-1] Predecessor gate | [ ] |
| [WEB-RUNTIME-2] Ignored remote preview environment contract | [ ] |
| [WEB-RUNTIME-3] README smoke procedure 연결 | [ ] |
| [WEB-RUNTIME-4] Remote server reachability and user evidence handoff | [ ] |
## 구현 체크리스트
- [ ] `01_web_scaffold` predecessor complete log를 확인한다.
- [ ] remote preview 실행에 필요한 ignored environment variable contract를 `agent-test/local/runtime-env.md` 또는 별도 ignored profile에 정리한다.
- [ ] `apps/flutter-test/README.md`에 web runtime smoke 절차를 환경값 없이 연결한다.
- [ ] 원격 preview server reachability를 검증하고 사용자 browser smoke evidence 수집 조건을 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
## 코드리뷰 전용 체크리스트
> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
- [ ] `코드리뷰 결과``PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [ ] 판정과 Required/Suggested/Nit 분류가 서로 일치한다.
- [ ] PASS이면 `complete.log`를 작성하고 active task directory archive 준비를 한다.
## 구현 에이전트 기록
### 변경 요약
_구현 에이전트가 실제 변경 요약을 작성한다._
### 계획 대비 변경 사항
_계획과 달라진 점이 없으면 `없음`이라고 쓴다._
### 검증 결과
_실행한 명령과 실제 stdout/stderr를 붙인다. 출력이 길면 저장 경로와 저장 명령을 기록한다._
### 남은 위험
_남은 위험이 없으면 `없음`이라고 쓴다._
## 사용자 리뷰 요청
_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 구현 에이전트는 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._
- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음
## 코드리뷰 결과
_리뷰 에이전트가 판정을 append한다._

View file

@ -75,6 +75,42 @@ This harness does not own default host, port, credential, or forwarding values.
Android/iOS/device smoke tests and browser previews should receive runtime URLs
from the invoking shell or ignored local profiles.
For Flutter Web browser notification smoke, load the ignored local preview
profile before starting the remote web server. Keep the actual host, port,
container, and forwarded URL values in `agent-test/local/web-smoke.env` or the
invoking shell.
```sh
set -a
source ../../agent-test/local/web-smoke.env
set +a
ssh "$NEXO_REMOTE_SSH" "zsh -lc 'docker exec ${NEXO_PREVIEW_CONTAINER} sh -lc \"cd ${NEXO_CONTAINER_REPO}/apps/flutter-test && flutter build web\"'"
ssh "$NEXO_REMOTE_SSH" "zsh -lc 'docker exec ${NEXO_PREVIEW_CONTAINER} sh -lc \"cd ${NEXO_CONTAINER_REPO}/apps/flutter-test && flutter run -d web-server --web-hostname ${NEXO_WEB_HOSTNAME} --web-port ${NEXO_CONTAINER_WEB_PORT}\"'"
```
In a separate shell, verify the forwarded preview URL responds:
```sh
set -a
source ../../agent-test/local/web-smoke.env
set +a
ssh "$NEXO_REMOTE_SSH" "zsh -lc 'curl -fsS ${NEXO_BROWSER_PREVIEW_URL} >/dev/null'"
```
Open the forwarded localhost URL in a browser and use the web smoke controls to
verify:
- `Refresh web permission` reports browser notification support and the current
permission state.
- `Request web permission` triggers the browser permission prompt and updates
the permission status.
- `Show web smoke notification` updates `Last web display` to `shown` when
permission is granted and a visible browser notification appears.
- Clicking the browser notification updates `Last opened` and `Last navigation`
for the smoke channel payload.
For Android FCM smoke testing, make sure the Android app has the required
Firebase configuration, including `android/app/google-services.json`.
Use the plugin-owned

View file

@ -6,6 +6,11 @@ root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
if [ -f "$root/packages/messaging_flutter/pubspec.yaml" ]; then
if command -v flutter >/dev/null 2>&1; then
(cd "$root/packages/messaging_flutter" && flutter test)
if [ "${NEXO_FLUTTER_WEB_TEST:-0}" = "1" ]; then
(cd "$root/packages/messaging_flutter" && flutter test --platform chrome)
else
echo "skip packages/messaging_flutter Chrome tests: set NEXO_FLUTTER_WEB_TEST=1 to run Flutter web tests"
fi
else
echo "skip packages/messaging_flutter: flutter not found"
fi
@ -30,4 +35,3 @@ if [ -f "$root/services/core/server/go.mod" ]; then
echo "skip services/core/server: set NEXO_CORE_GO_TEST=1 to run the full Go test suite"
fi
fi

View file

@ -372,40 +372,6 @@ void main() {
});
});
group('NexoMessagingPlugin web notification permission', () {
late NexoMessagingPlugin plugin;
setUp(() {
plugin = NexoMessagingPlugin.instance;
});
test('reports unsupported status on non-web platforms', () async {
final status = await plugin.getWebNotificationPermissionStatus();
expect(status.isSupported, isFalse);
expect(
status.permission,
NexoMessagingWebNotificationPermission.unsupported,
);
expect(status.rawPermission, isNull);
expect(status.isGranted, isFalse);
});
test(
'request is a no-op unsupported status on non-web platforms',
() async {
final status = await plugin.requestWebNotificationPermission();
expect(status.isSupported, isFalse);
expect(
status.permission,
NexoMessagingWebNotificationPermission.unsupported,
);
expect(status.rawPermission, isNull);
},
);
});
group('NexoMessagingWebNotificationStatus', () {
test('normalizes browser permission values', () {
final granted = NexoMessagingWebNotificationStatus.fromBrowserPermission(

View file

@ -0,0 +1,41 @@
@TestOn('vm')
library;
import 'package:flutter_test/flutter_test.dart';
import 'package:nexo_messaging/nexo_messaging.dart';
void main() {
group('NexoMessagingPlugin web notification permission on VM', () {
late NexoMessagingPlugin plugin;
setUp(() {
plugin = NexoMessagingPlugin.instance;
});
test('reports unsupported status on non-web platforms', () async {
final status = await plugin.getWebNotificationPermissionStatus();
expect(status.isSupported, isFalse);
expect(
status.permission,
NexoMessagingWebNotificationPermission.unsupported,
);
expect(status.rawPermission, isNull);
expect(status.isGranted, isFalse);
});
test(
'request is a no-op unsupported status on non-web platforms',
() async {
final status = await plugin.requestWebNotificationPermission();
expect(status.isSupported, isFalse);
expect(
status.permission,
NexoMessagingWebNotificationPermission.unsupported,
);
expect(status.rawPermission, isNull);
},
);
});
}

View file

@ -0,0 +1,19 @@
@TestOn('browser')
library;
import 'package:flutter_test/flutter_test.dart';
import 'package:nexo_messaging/nexo_messaging.dart';
import 'package:nexo_messaging/src/web/browser_notification_interop_web.dart';
void main() {
test('browser Notification API is visible in Chrome runtime', () {
expect(BrowserNotificationInteropImpl().isSupported, isTrue);
});
test('plugin reports browser permission status in Chrome runtime', () async {
final status =
await NexoMessagingPlugin.instance.getWebNotificationPermissionStatus();
expect(status.isSupported, isTrue);
expect(status.rawPermission, isNotNull);
});
}