@hungvv/super-ads-skills 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +71 -13
  2. package/dist/cli.js +8 -2
  3. package/package.json +1 -1
  4. package/skills/README.md +4 -0
  5. package/skills/adspro-to-superads/SKILL.md +157 -732
  6. package/skills/adspro-to-superads/references/global-invariant-check.md +49 -0
  7. package/skills/adspro-to-superads/references/migration-contract.md +57 -0
  8. package/skills/adspro-to-superads/references/phase-0-inventory.md +39 -0
  9. package/skills/adspro-to-superads/references/phase-1-2-gradle-manifest.md +85 -0
  10. package/skills/adspro-to-superads/references/phase-3-config-migration.md +159 -0
  11. package/skills/adspro-to-superads/references/phase-4-wrapper-observability.md +70 -0
  12. package/skills/adspro-to-superads/references/phase-5-7-callsites-layout-cleanup.md +73 -0
  13. package/skills/adspro-to-superads/references/principles-and-authority.md +73 -0
  14. package/skills/adspro-to-superads/references/user-questions.md +53 -0
  15. package/skills/adspro-to-superads/snippets/ads-api-quick.md +20 -0
  16. package/skills/adspro-to-superads/templates/migration-inventory.md +42 -0
  17. package/skills/super-ads-ab-test/SKILL.md +91 -23
  18. package/skills/super-ads-adb-test/SKILL.md +85 -36
  19. package/skills/super-ads-adb-test/{references → examples}/scenarios-sample.md +5 -5
  20. package/skills/super-ads-add-placement/SKILL.md +145 -50
  21. package/skills/super-ads-add-placement/references/call-site-api.md +33 -0
  22. package/skills/super-ads-add-placement/snippets/app-open.md +25 -0
  23. package/skills/super-ads-add-placement/snippets/fullscreen-nav.md +14 -0
  24. package/skills/super-ads-add-placement/snippets/inline-banner-native.md +19 -0
  25. package/skills/super-ads-add-placement/snippets/preload-event.md +13 -0
  26. package/skills/super-ads-add-placement/snippets/reward.md +17 -0
  27. package/skills/super-ads-config/SKILL.md +94 -36
  28. package/skills/super-ads-debug/SKILL.md +87 -37
  29. package/skills/super-ads-debug/references/logging-setup.md +2 -0
  30. package/skills/super-ads-debug/scripts/filter-logads.sh +21 -0
  31. package/skills/super-ads-debug-override/SKILL.md +154 -81
  32. package/skills/super-ads-debug-override/snippets/arm-override.md +9 -0
  33. package/skills/super-ads-debug-override/snippets/check-module.md +8 -0
  34. package/skills/super-ads-debug-override/snippets/clear-override.md +9 -0
  35. package/skills/super-ads-debug-override/snippets/confirm-active.md +16 -0
  36. package/skills/super-ads-guide/SKILL.md +129 -0
  37. package/skills/super-ads-guide/references/compatibility.md +26 -0
  38. package/skills/super-ads-guide/references/sdk-version-check.md +50 -0
  39. package/skills/super-ads-integrate/SKILL.md +145 -47
  40. package/skills/super-ads-integrate/references/application-setup.md +2 -21
  41. package/skills/super-ads-integrate/references/gradle-setup.md +1 -13
  42. package/skills/super-ads-integrate/snippets/consent-request.md +12 -0
  43. package/skills/super-ads-integrate/templates/application-oncreate.md +17 -0
  44. package/skills/super-ads-integrate/templates/gradle-dependencies.md +17 -0
  45. package/skills/super-ads-release-check/SKILL.md +85 -32
  46. package/skills/super-ads-show-rate/SKILL.md +87 -36
  47. package/skills/super-ads-show-rate/references/collect-snippet.md +2 -36
  48. package/skills/super-ads-show-rate/scripts/show-rate.sh +25 -0
  49. package/skills/super-ads-show-rate/snippets/show-events-logger.md +26 -0
  50. package/skills/super-ads-upgrade/SKILL.md +137 -0
  51. package/skills/super-ads-upgrade/references/upgrade-hops.md +26 -0
  52. package/skills/super-ads-upgrade/templates/changelog-template.md +39 -0
  53. package/skills/super-ads-add-placement/references/call-site-snippets.md +0 -90
  54. /package/skills/super-ads-ab-test/{references → templates}/firebase-handoff-template.md +0 -0
  55. /package/skills/super-ads-config/{references → examples}/patch-examples.md +0 -0
@@ -0,0 +1,53 @@
1
+ # Câu hỏi phải hỏi user (Nhóm A-D)
2
+
3
+ Mỗi câu hỏi phải có **phương án khuyến nghị** và nêu **hệ quả**. Agent không được tự chọn thay
4
+ user ở nhóm A và B. Gộp câu hỏi cùng nhóm vào **một** lần hỏi.
5
+
6
+ - Nhóm B: hỏi khi lập inventory Phase 0.
7
+ - Nhóm A và D: hỏi **trước** Phase 3.
8
+ - Nhóm C: hỏi **một lần** đầu Phase 4.
9
+
10
+ Mọi câu trả lời ghi vào mục "Decisions" trong `migration-inventory.md`.
11
+
12
+ ## Nhóm A — tính năng không chuyển được (loại C)
13
+
14
+ | Tình huống | Câu hỏi | Phương án gợi ý |
15
+ |---|---|---|
16
+ | App dùng `AdmobNativePip` | SuperAds không có native PIP. Xử lý placement này thế nào? | (1) Bỏ PIP, chuyển thành `NATIVE` thường ở cùng vị trí — khuyến nghị; (2) Giữ AdsPro riêng cho PIP — không khuyến nghị, hai SDK cùng tồn tại; (3) Tạm tắt placement |
17
+ | App dùng `AdmobNativeCollapsibleHalfSize` | Không có half-size. Dùng gì thay? | (1) `NATIVE_COLLAPSIBLE` với layout expanded nhỏ hơn — khuyến nghị; (2) Bỏ, dùng `NATIVE` |
18
+ | Space có `adsType` không nằm trong bảng map | `adsType` này không có format tương ứng. Ý định sản phẩm là gì? | Liệt kê 2–3 format gần nhất kèm khác biệt hành vi |
19
+
20
+ ## Nhóm B — behavior không suy ra được từ code
21
+
22
+ | Tình huống | Câu hỏi | Phương án gợi ý |
23
+ |---|---|---|
24
+ | Code cũ nav ở cả hai callback, hoặc nav ngoài callback | Placement này nav khi ad *hiện* hay khi ad *đóng*? | Mặc định SDK là `NAVIGATE_ON_DISMISS`; nêu hệ quả UX từng lựa chọn |
25
+ | `load()` gọi trong `onCreate` của Activity, không thuộc màn nào | Preload này nên gắn với event màn nào? | Đề xuất màn gần nhất trong flow + phương án preload ngay sau init |
26
+ | Không rõ preload áp cho phiên nào | Preload cho người mở lần đầu, người quay lại, hay cả hai? | Khuyến nghị **cả hai** (`_fo` + `_fn`) nếu code cũ preload vô điều kiện |
27
+ | Reload cũ vừa có timer vừa có click | Giữ cả `reload.auto` và `reload.click`, hay chỉ một? | Chain chỉ nhận click |
28
+ | Space trong JSON nhưng zero call site (vd `Banner_chung`) | Giữ placement này hay bỏ? | (1) Giữ, ghi vào Documented exclusions — khuyến nghị (an toàn cho RC); (2) Bỏ khỏi config |
29
+ | Hai space khác nhau nhưng cùng ý nghĩa | Gộp hay giữ tách? | Khuyến nghị **giữ tách** để bảo toàn analytics |
30
+ | Event cũ mang `previous_screen`/`next_screen` trong bundle | Event khai trong JSON không mang được cặp screen. Bỏ cặp screen, hay giữ tracking app-side? | (1) Bỏ, dùng `adItemId` — khuyến nghị; (2) Collect `TrackerEvent.Impression` rồi tự ghép screen từ state app |
31
+ | Tên event analytics cũ rải rác trong Kotlin | Tên nào đưa vào `tracking.event*`, tên nào giữ app-side? | Event AB/theo placement vào JSON; event bespoke cần ngữ cảnh app thì giữ trên flow |
32
+
33
+ ## Nhóm C — quyết định kiến trúc (đầu Phase 4)
34
+
35
+ | Câu hỏi | Phương án gợi ý |
36
+ |---|---|
37
+ | Nhà cho wrapper: moi ruột `AdsUtils.kt` cũ, hay tạo `AdsSP.kt` mới? | (1) Moi ruột file cũ — **khuyến nghị**, giữ path nên ~40 màn không đổi import; (2) File mới kiểu SlideShow — sạch tên nhưng phải sửa import ở mọi màn |
38
+ | Nhà cho `EventScreen`: thêm vào file base có sẵn hay tạo file mới? | (1) Thêm vào file base sẵn có; (2) File mới `EventScreen.kt` nếu package base không có nhà hợp lý |
39
+ | Có dọn tham số inert trong migration không? | Khuyến nghị **không** — tách commit riêng sau khi verify xong |
40
+ | Config: một file JSON asset, hay thêm nhánh Remote Config ngay? | Khuyến nghị asset trước, RC sau khi verify |
41
+
42
+ ## Nhóm D — hạ tầng (hỏi ngay khi phát hiện)
43
+
44
+ | Tình huống | Câu hỏi |
45
+ |---|---|
46
+ | Config có network nhưng thiếu module | Config có `"network": "CloudX"` nhưng chưa có `SuperAdsCloudX`. Thêm module hay bỏ network khỏi config? |
47
+ | Thiếu `io.cloudx.APP_KEY` / `applovin.sdk.key` | Cung cấp key, hay bỏ network đó? |
48
+ | App chưa có `screenName()` / registry tracking | Không có gì dựng chuỗi event preload. Wire tracking screen trước, hay preload theo cách khác? |
49
+ | App có RC key timing ads (tên tuỳ app, vd `keyTimeBetweenAdInter`) | JSON chỉ có `show.timeBetweenMs` cố định. Ops còn chỉnh nóng qua RC không? |
50
+ | Có native-sau-inter | Production: mấy native/lần inter? RC/AB nào (nếu có) tắt native phụ? Counter `% N` ra pos nào? Điền JSON theo đo, không theo template |
51
+ | Click reload cùng space, khác layout | Tách twin SuperAds theo Bảng D, chung unit nếu AdsPro chung `ids[]` |
52
+ | `minimumFetchIntervalInSeconds` | SlideShow đặt `0` (fetch mọi lần). Giữ `0` hay đặt giá trị an toàn hơn cho production? |
53
+ | App đã có AppsFlyer / Adjust / Meta | Giữ nguyên kênh nào? `SuperAdsTracking` là **mặc định nên có** (Phase 1) — thiếu nó là mất `ad_impression` / `ad_click` Firebase (`MIGRATION.md:452`). Chỉ bỏ khi app tự bắn doanh thu Firebase ở chỗ khác và user xác nhận |
@@ -0,0 +1,20 @@
1
+ # Ads API — tra nhanh
2
+
3
+ ```kotlin
4
+ // Init
5
+ Ads.init(application, configProvider = { getConfig(...) }, isDebug = isDebug)
6
+ Ads.isPremium = purchased
7
+ // Consent TRƯỚC preload/show/app open (core không tự chặn): Activity đầu
8
+ Ads.gdpr.requestAndShowIfRequired(activity, isDebug, timeoutMs = /* timeout AdsPro của app */) { onConsentDone(); next() }
9
+
10
+ // Inline (native / banner)
11
+ Ads.show(placementId, activity, AdTarget.AdView(container, lifecycle), callback)
12
+
13
+ // Fullscreen / reward
14
+ Ads.show(placementId, activity, callback = NavAdCallback { ... })
15
+ Ads.show(placementId, activity, callback = RewardAdCallback(true) { ... })
16
+
17
+ // Preload — KHÔNG gọi thủ công. EventScreen + preload.eventActive.
18
+ Ads.dispatchEvent(activity, "create_open_screen_5_fo")
19
+ ```
20
+ ```
@@ -0,0 +1,42 @@
1
+ # migration-inventory.md — mẫu Bảng A-D
2
+
3
+ ## Bảng A — placement identity + behavior
4
+
5
+ | spaceName | adsType | ids[] | layout collapsed | layout expanded | show API cũ | nav từ callback nào | reload trigger cũ | space reload cũ | RC key | placement | format | mode.show | mode.navigate | status |
6
+ |---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
7
+ | Native_Home | native | 1 | native_collap_small | - | show | - | click | Native_Reload | config_ads_22_4 | Native_Home | NATIVE | LOAD_AND_SHOW | - | TODO |
8
+ | Interstitial_Chung | interstitial | 1 | - | - | show + gate LOADED | onAdDismissed | - | - | config_ads_22_4 | Interstitial_Chung | INTER | SHOW_LOADED | NAVIGATE_ON_DISMISS | TODO |
9
+
10
+ Cột `placement` = nguyên văn `spaceName`. **MUST NOT CHANGE.**
11
+
12
+ ## Bảng B — preload moment (một hàng mỗi call site `load()`)
13
+
14
+ | File:line | space | màn đang đứng | screenName() | thời điểm | chuỗi event | status |
15
+ |---|---|---|---|---|---|---|
16
+ | LanguageFragment.kt:45 | Native_Onboarding | Language | open_screen_1 | onViewReady | create_open_screen_1_fo | TODO |
17
+
18
+ Không gom nhiều `load()` của cùng space thành một hàng. Mỗi thời điểm là một hàng.
19
+
20
+ ## Bảng C — cặp reload
21
+
22
+ | placement nguồn | trigger | placement đích | chu kỳ (ms) | key JSON | status |
23
+ |---|---|---|---|---|---|
24
+ | Native_Home | click | Native_Reload | - | reload.click.placementID | TODO |
25
+ | Native_Record_Video | auto | Native_Record_Video_ReLoad_15s | 15000 | reload.auto.placementID + show.timeAutoReloadMs | TODO |
26
+
27
+ ## Bảng D — click reload theo layout (khi app có click reload)
28
+
29
+ Bảng C gom trigger. Bảng D vì SDK bind layout trên **adItem đích**. Hàng mẫu chỉ hiểu cột —
30
+ điền space/layout/unit **của app này**. Tách twin **chỉ khi** layout hoặc unit lúc click khác nhau.
31
+
32
+ | nguồn | layout lúc show | unit AdsPro lúc click | SuperAds reload placement | unit | layout đích | self-click? |
33
+ |---|---|---|---|---|---|---|
34
+ | *(space)* | *(xml)* | *(ids click)* | *(space reload cũ hoặc twin mới)* | *(khớp AdsPro)* | *(= layout show)* | *(click lại cùng space?)* |
35
+
36
+ Space reload **zero call site** → Exclusions, không làm đích vì tên.
37
+
38
+ ## Các mục khác trong cùng file
39
+
40
+ - **Decisions** — câu trả lời nhóm A/B/C/D.
41
+ - **Inert parameters** — tham số giữ chữ ký nhưng không còn tác dụng.
42
+ - **Documented exclusions** — space được giữ / bỏ có lý do (vd `Banner_chung` zero call site).
@@ -1,33 +1,50 @@
1
1
  ---
2
2
  schema: 1
3
3
  name: super-ads-ab-test
4
- description: Use when the user wants a Firebase A/B test of SuperAds config — confirm the hypothesis, generate the two variant JSON files with make_ab_variants, and hand the user exact Firebase Console instructions (parameter, activation event, tracking); the agent never touches Firebase or app code.
5
- version: 1.0.0
4
+ description: Use when the user wants a Firebase A/B test of SuperAds config, generating two variant JSON files and handoff steps
5
+ version: 1.1.0
6
6
  group: Ads
7
+ superAds: ">=4.0.0 <5.0.0"
7
8
  ---
8
9
 
9
10
  # Tạo A/B test config SuperAds cho Firebase
10
11
 
11
12
  Agent làm đúng 3 việc: **chốt A/B là gì với user** → **sinh 2 file config** → **bàn giao hướng dẫn Firebase**. Agent **không** thao tác Firebase Console, **không** sửa code app, **không** sửa asset hay working config.
12
13
 
13
- | Cần | Tài liệu |
14
- |---|---|
15
- | Mẫu tin nhắn bàn giao Firebase (bắt buộc dùng) | [references/firebase-handoff-template.md](references/firebase-handoff-template.md) |
16
- | Hợp đồng SDK (activation, `ab_variant`, provenance) | `MIGRATION.md`, mục "A/B test bằng remote config" |
17
- | Đối soát sau khi chạy (BigQuery, quy tắc lọc) | [../super-ads-release-check/references/firebase-ab-checklist.md](../super-ads-release-check/references/firebase-ab-checklist.md) |
18
- | Tool sinh variant | `make_ab_variants` (`tools/ai_agent_tools/src/mcp/tools.js:254-278`): generate-only, tự chặn variant lệch ngoài path được đổi, trả `validationA` / `validationB` |
19
- | Overload nạp JSON có cờ activated | `SA/api/Ads.kt:197` |
20
- | Luật tên event | `super-ads-tracking/src/main/java/com/android/fullhd/super_ads/tracking/gateway/FirebaseEventName.kt:33-40` |
21
-
22
14
  ## When to use
23
15
  - "Làm A/B test cooldown inter 30s vs 60s", "test bật/tắt native ở màn X", "chia 2 nhóm config qua Firebase".
24
16
 
25
- ## When NOT to use
17
+ ## 🚫 When NOT to use
26
18
  - Chỉ đổi một giá trị config cho mọi user → `super-ads-config`.
27
19
  - Chạy app với config khác asset để test cục bộ → `super-ads-debug-override`.
28
20
  - Đọc kết quả / đối soát experiment đã chạy → `super-ads-release-check` (checklist Firebase A/B).
29
21
 
30
- ## Quy trình
22
+ ## 📋 Prerequisites
23
+ - Định tuyến skill và kiểm version SDK: xem [super-ads-guide](../super-ads-guide/SKILL.md).
24
+ - Skill này nhắm SuperAds `>=4.0.0 <5.0.0`. App dùng SuperAds thấp hơn ⇒ **dừng** và khuyến nghị (không ép) nâng cấp qua [super-ads-upgrade](../super-ads-upgrade/SKILL.md) trước khi tiếp tục.
25
+ - MCP `super-ads` đã kết nối (`read_working_config`, `make_ab_variants`).
26
+ - App đã có đường nạp Remote Config có cờ activated (kiểm ở Workflow bước 1). Hợp đồng SDK (activation, `ab_variant`, provenance): `MIGRATION.md`, mục "A/B test bằng remote config".
27
+
28
+ ## ⚡ Quick Reference
29
+
30
+ | Cần | Tài liệu |
31
+ |---|---|
32
+ | Mẫu tin nhắn bàn giao Firebase (bắt buộc dùng) | [templates/firebase-handoff-template.md](templates/firebase-handoff-template.md) |
33
+ | Đối soát sau khi chạy (BigQuery, quy tắc lọc) | [../super-ads-release-check/references/firebase-ab-checklist.md](../super-ads-release-check/references/firebase-ab-checklist.md) |
34
+
35
+ Skill này không có `references/`, `snippets/`, `examples/` hay `scripts/` riêng.
36
+
37
+ ## 🏗️ Recommended Architecture
38
+ Hai file variant chỉ khác nhau ở các path đã chốt và `global.version`. Cả hai mang **cùng** activation event để Firebase đếm user ở cả hai nhóm; `ab_variant` (`<exp>_A` / `<exp>_B`) dùng khi phân tích.
39
+
40
+ ## Workflow
41
+
42
+ ### Stop conditions
43
+ - App không có `loadFromJson(json, firebaseActivated = true)` đọc từ Remote Config (bước 1).
44
+ - User chưa xác nhận bảng A/B (bước 2).
45
+ - Working config không phải asset app đang nạp.
46
+ - Version trùng, tên event sai luật hoặc trùng exposure.
47
+ - `make_ab_variants` báo invariant / validation lỗi, hoặc `diffAB` lệch bảng đã chốt.
31
48
 
32
49
  ### 1. Kiểm app có đường nạp Remote Config đúng (điểm dừng)
33
50
  Tìm trong code app lời gọi `Ads.loadFromJson(json, firebaseActivated = true)` và **tên tham số Remote Config** mà chỗ đó đọc (app mẫu: `ads_config_v2` trong `app/src/main/java/com/android/hd/ads2026/RemoteConfigAbLoader.kt`). Đồng thời xác nhận giá trị chỉ được nạp khi đến từ remote sau `fetchAndActivate()`.
@@ -67,25 +84,76 @@ Rồi trình **bảng xác nhận** và chờ user trả lời "đúng" (hoặc
67
84
  7. Đối chiếu `diffAB` với bảng đã chốt: hai file chỉ được khác nhau ở các path trong bảng + `global.version`. Khác thêm ⇒ dừng, báo user.
68
85
 
69
86
  ### 4. Bàn giao Firebase
70
- Điền [references/firebase-handoff-template.md](references/firebase-handoff-template.md) và gửi user, đủ mọi mục. Kết thúc ở đây: user tự cấu hình Firebase.
87
+ Điền [templates/firebase-handoff-template.md](templates/firebase-handoff-template.md) và gửi user, đủ mọi mục. Kết thúc ở đây: user tự cấu hình Firebase.
71
88
 
72
- ## Contract
73
- **MUST**
89
+ ## 🔧 API Reference
90
+
91
+ | Mục | Mô tả | Nguồn |
92
+ |---|---|---|
93
+ | `make_ab_variants` | Generate-only, tự chặn variant lệch ngoài path được đổi, trả `validationA` / `validationB` | `tools/ai_agent_tools/src/mcp/tools.js:254-278` |
94
+ | Overload nạp JSON có cờ activated | `Ads.loadFromJson(json, firebaseActivated = true)` | `SA/api/Ads.kt:197` |
95
+ | Luật tên event | Giới hạn tên activation / exposure | `super-ads-tracking/src/main/java/com/android/fullhd/super_ads/tracking/gateway/FirebaseEventName.kt:33-40` |
96
+
97
+ ## ✅ Best Practices
74
98
  - Điểm dừng ở bước 1 và bước 2; không có xác nhận "đúng" của user thì không sinh file.
75
99
  - `global.version` của A và B khác nhau, ổn định, không trùng version asset.
76
100
  - Activation event **cùng tên** ở A và B; mỗi experiment một tên riêng.
77
101
  - Nói rõ cho user: tên tham số Remote Config, file nào vào Baseline / Variant, tên activation event, goal, các event và param tracking.
78
102
 
79
- **MUST NOT**
103
+ ## ❌ Anti-patterns
80
104
  - Không thao tác Firebase Console, không gọi API Firebase.
81
105
  - Không sửa code app, asset hay working config: không `apply_patch`, `replace_working_config`, `sync_to_source`.
82
106
  - Không tự chọn giá trị thử nghiệm, % user hay tên experiment thay user.
83
107
  - Không khai `activation_event` vào asset.
84
108
  - Không đặt tên activation trùng tên exposure hay tên reserved.
85
109
 
86
- ## Stop conditions
87
- - App không có `loadFromJson(json, firebaseActivated = true)` đọc từ Remote Config (bước 1).
88
- - User chưa xác nhận bảng A/B (bước 2).
89
- - Working config không phải asset app đang nạp.
90
- - Version trùng, tên event sai luật hoặc trùng exposure.
91
- - `make_ab_variants` báo invariant / validation lỗi, hoặc `diffAB` lệch bảng đã chốt.
110
+ ## ⚠️ Common Issues
111
+
112
+ | Problem | Cause | Solution |
113
+ |---|---|---|
114
+ | Firebase không đếm được user | App gọi `loadFromJson(json)` không cờ activated nên activation event không bắn | Dừng ở bước 1, trỏ user tới `MIGRATION.md`, không tự viết code app |
115
+ | `make_ab_variants` báo invariant / validation lỗi | Variant lệch ngoài path được đổi hoặc config không hợp lệ | Dừng, báo user, không ghi file |
116
+
117
+ ## Files created
118
+ Hai file variant (JSON) trong gốc repo của app, do agent ghi sau khi user xác nhận bảng A/B:
119
+ - `super-ads-ab-test/<exp>/variant_A.json`
120
+ - `super-ads-ab-test/<exp>/variant_B.json`
121
+
122
+ ## Files modified
123
+ Chỉ `.gitignore` ở gốc repo (thêm dòng `/super-ads-ab-test/` nếu chưa có). Không sửa code app, asset hay working config.
124
+
125
+ ## Verification
126
+ - `invariantsA` / `invariantsB` không có vi phạm; `validationA` / `validationB` không có error.
127
+ - `diffAB` chỉ khác nhau ở các path trong bảng đã chốt + `global.version`.
128
+ - `<exp>_A` ≠ `<exp>_B`, cả hai ≠ `global.version` hiện tại; tên activation hợp lệ và không trùng exposure.
129
+
130
+ ## Checklist
131
+ - [ ] App có đường nạp `loadFromJson(json, firebaseActivated = true)` từ Remote Config.
132
+ - [ ] User xác nhận bảng A/B.
133
+ - [ ] Working config đúng là asset app đang nạp.
134
+ - [ ] Hai file variant sinh xong, `diffAB` khớp bảng.
135
+ - [ ] `.gitignore` có `/super-ads-ab-test/`.
136
+ - [ ] Đã gửi bản bàn giao Firebase đủ mọi mục.
137
+
138
+ ## 📈 Performance Notes
139
+ > **Not applicable for this skill.**
140
+
141
+ ## 🔒 Security Notes
142
+ > **Not applicable for this skill.**
143
+
144
+ ## 🔄 Migration Guide
145
+ > **Not applicable for this skill.**
146
+
147
+ ## Output
148
+ Đường dẫn hai file variant, bảng A/B đã chốt, và bản bàn giao Firebase đã điền từ template (tham số Remote Config, file Baseline / Variant, activation event, goal, event và param tracking).
149
+
150
+ ## Examples
151
+ - [templates/firebase-handoff-template.md](templates/firebase-handoff-template.md): mẫu bàn giao đã có đủ mục để điền.
152
+
153
+ ## 📚 References
154
+ - [super-ads-guide](../super-ads-guide/SKILL.md), [super-ads-upgrade](../super-ads-upgrade/SKILL.md)
155
+ - [super-ads-config](../super-ads-config/SKILL.md), [super-ads-debug-override](../super-ads-debug-override/SKILL.md), [super-ads-release-check](../super-ads-release-check/SKILL.md)
156
+ - `MIGRATION.md`, mục "A/B test bằng remote config"
157
+
158
+ ## 🏷️ Tags
159
+ `super-ads` `ab-test` `firebase` `remote-config` `variants` `experiment`
@@ -1,54 +1,53 @@
1
1
  ---
2
2
  schema: 1
3
3
  name: super-ads-adb-test
4
- description: Use when you need to verify SuperAds behaviour on a real Android device or emulator without changing the app — build, install, drive the UI, capture logcat and check each scenario step against log/UI expectations.
5
- version: 1.0.0
4
+ description: Use when verifying SuperAds behaviour on a device or emulator by running do/expect scenarios without editing the app
5
+ version: 1.1.0
6
6
  group: Ads
7
+ superAds: ">=4.0.0 <5.0.0"
7
8
  ---
8
9
 
9
10
  # Test SuperAds trên thiết bị (không sửa app)
10
11
 
11
12
  Chạy kịch bản `do` / `expect` trên thiết bị: build + cài app, điều khiển UI, thu Logcat, so từng bước với kỳ vọng, báo `PASS` / `FAIL` / `SKIP` / `UNKNOWN` kèm bằng chứng.
12
13
 
13
- | Bước | Tài liệu |
14
- |---|---|
15
- | Định dạng kịch bản | [references/scenario-format.md](references/scenario-format.md) |
16
- | Kịch bản mẫu | [references/scenarios-sample.md](references/scenarios-sample.md) |
17
- | Regex log theo sự kiện | [references/log-assertions.md](references/log-assertions.md) |
18
- | App mẫu trong repo (ví dụ) | [references/sample-app-notes.md](references/sample-app-notes.md) |
19
- | Bật log SDK | [../super-ads-debug/references/logging-setup.md](../super-ads-debug/references/logging-setup.md) |
20
-
21
14
  ## When to use
22
15
  - Kiểm một placement mới gắn, một thay đổi config, hoặc tái hiện lỗi trên máy thật.
23
16
  - Chạy lặp lại cùng một kịch bản trước/sau khi sửa (dùng cho `super-ads-debug`, `super-ads-show-rate`, `super-ads-add-placement`).
24
17
 
25
- ## When NOT to use
18
+ ## 🚫 When NOT to use
26
19
  - Kiểm logic SDK không cần máy: bộ JVM/Robolectric `ScenarioRunner` (`./gradlew superAdsLogicVerification`, `super-ads-test/README-scenarios.md:9-20`).
27
20
  - Instrumentation với ad thật cho SDK: `scripts/verify-all.sh`, `super-ads-test/README-real-ads-instrumentation.md`.
28
- - Tìm nguyên nhân một lỗi: `super-ads-debug` (skill này chỉ chạy và báo kết quả).
21
+ - Tìm nguyên nhân một lỗi: [super-ads-debug](../super-ads-debug/SKILL.md) (skill này chỉ chạy và báo kết quả).
22
+
23
+ ## 📋 Prerequisites
24
+ - Routing và kiểm version SDK: [super-ads-guide](../super-ads-guide/SKILL.md).
25
+ - Skill này nhắm SuperAds `>=4.0.0 <5.0.0`. App dùng SuperAds thấp hơn thì **dừng** và khuyến nghị (không ép) nâng cấp bằng [super-ads-upgrade](../super-ads-upgrade/SKILL.md) trước khi tiếp tục.
26
+ - Có thiết bị: `adb devices` có ít nhất một máy ở trạng thái `device`. Nhiều máy thì chỉ định serial (`adb -s <serial>`), như `scripts/verify-all.sh:21-22`.
27
+ - Coi applicationId, Activity khởi động, tag log, màn hình là **tham số**. Đọc từ `build.gradle`, `AndroidManifest.xml`, code `Application` của app đang test.
28
+ - Biết config đang nạp (lời gọi `Ads.init` trong `Application`); chỉ dùng placement có thật trong đó.
29
+ - Log SDK đã bật ở bản đang cài (cách bật: [logging-setup.md](../super-ads-debug/references/logging-setup.md) mục 2).
30
+
31
+ ## ⚡ Quick Reference
32
+ | Cần | Mở |
33
+ |---|---|
34
+ | Định dạng kịch bản (`do` / `expect`, quy tắc) | [references/scenario-format.md](references/scenario-format.md) |
35
+ | Kịch bản mẫu S1-S6 | [examples/scenarios-sample.md](examples/scenarios-sample.md) |
36
+ | Regex log theo sự kiện (thành công, blocked, error) | [references/log-assertions.md](references/log-assertions.md) |
37
+ | App mẫu trong repo (ví dụ) | [references/sample-app-notes.md](references/sample-app-notes.md) |
38
+ | Bật log SDK, file `.logads` | [../super-ads-debug/references/logging-setup.md](../super-ads-debug/references/logging-setup.md) |
29
39
 
30
- ## Authority order
40
+ Trạng thái kết quả: `PASS` / `FAIL` / `SKIP (lý do)` / `UNKNOWN (lý do)`.
41
+
42
+ ## 🏗️ Recommended Architecture
43
+ Thứ tự nguồn sự thật:
31
44
  1. Code SDK (chuỗi log, mã lỗi) và code app đang test (màn hình, id, tag log).
32
45
  2. Config đang được app nạp.
33
46
  3. Tài liệu skill. Nhãn nút, id view trong tài liệu là của app mẫu.
34
47
 
35
- ## Contract
36
- **MUST**
37
- - Coi applicationId, Activity khởi động, tag log, màn hình là **tham số**. Đọc từ `build.gradle`, `AndroidManifest.xml`, code `Application` của app đang test.
38
- - Đọc config đang nạp trước (lời gọi `Ads.init` trong `Application`), chỉ dùng placement có thật trong đó.
39
- - Mỗi kịch bản: bắt đầu từ trạng thái log sạch (`adb logcat -c`, hoặc đánh dấu thời điểm để lấy file `.logads` mới) → `launch` → các bước → lưu file log riêng. Nguồn log ưu tiên là file `.logads`, Logcat là dự phòng ([logging-setup.md](../super-ads-debug/references/logging-setup.md) mục 6).
40
- - Mỗi kết luận `PASS` / `FAIL` trích dòng log hoặc trạng thái UI làm bằng chứng.
41
- - Trả lại trạng thái máy đã đổi (mạng, xoay màn) kể cả khi kịch bản fail.
42
- - Có nhiều máy thì chỉ định serial (`adb -s <serial>`), như `scripts/verify-all.sh:21-22`.
43
-
44
- **MUST NOT**
45
- - Không sửa code, manifest, Gradle, asset config của app. Kể cả "tạm thời".
46
- - Không ghi đè file config của app bằng working config `tmp-*.json` của MCP.
47
- - Không bấm vào ad thật (click) trên bản production, và không chạy với unit thật khi chưa được user đồng ý (rủi ro invalid traffic).
48
- - Không báo `PASS` cho kỳ vọng `never` khi không có bằng chứng dương rằng lời gọi đã tới SDK ([log-assertions.md](references/log-assertions.md) mục 4).
49
- - Không chạy `network off` trên emulator/LDPlayer: mất luôn kết nối adb.
48
+ ## Workflow
50
49
 
51
- ## Stop conditions (dừng và hỏi user)
50
+ ### Dừng và hỏi user khi
52
51
  - `adb devices` không có máy nào ở trạng thái `device`.
53
52
  - Logcat không có dòng `SuperAdsSDK` sau `launch`: logger chưa bật ở bản đang cài. Muốn bật thì phải sửa app, nên hỏi user (cách bật: [logging-setup.md](../super-ads-debug/references/logging-setup.md) mục 2).
54
53
  - Kịch bản cần config khác với config app đang nạp. App có hook override (bản debug có `ConfigOverrideReceiver`) ⇒ dùng `super-ads-debug-override`, không phải sửa app. Không có hook ⇒ đưa user lựa chọn:
@@ -58,7 +57,7 @@ Chạy kịch bản `do` / `expect` trên thiết bị: build + cài app, điề
58
57
  - Config dùng unit thật và kịch bản có click hoặc show nhiều lần.
59
58
  - Build lỗi. Báo nguyên văn lỗi, không tự sửa Gradle.
60
59
 
61
- ## Phase 1: Chuẩn bị
60
+ ### Phase 1: Chuẩn bị
62
61
  1. `adb devices -l`. Chọn serial; ghi model và loại (máy thật hay emulator).
63
62
  2. Lấy tham số app: `applicationId` (`build.gradle`), Activity LAUNCHER (`AndroidManifest.xml`), tag log của app (`Application`), file config đang nạp.
64
63
  3. Build và cài bản debug: `./gradlew :<appModule>:assembleDebug`, rồi `adb -s <serial> install -r <apk>`. Ghi `versionName`.
@@ -68,7 +67,7 @@ Chạy kịch bản `do` / `expect` trên thiết bị: build + cài app, điề
68
67
 
69
68
  **Verify:** app đã cài (`adb shell pm path <pkg>` trả đường dẫn), có công cụ điều khiển UI.
70
69
 
71
- ## Phase 2: Kiểm điều kiện quan sát
70
+ ### Phase 2: Kiểm điều kiện quan sát
72
71
  1. Chọn nguồn log. **File `.logads`** (khi app debuggable và `isDebug = true` hoặc đã bật ghi file): ghi lại thời điểm bắt đầu, sau kịch bản lấy file mới nhất bằng `adb -s <serial> exec-out run-as <pkg> cat cache/logads/<file>.logads > <scenario>.logads`; mỗi kịch bản một file (app phải chạy lại để có file mới, hoặc cắt theo giờ). **Logcat** (dự phòng): `adb logcat -c`, rồi ghi log nền `adb -s <serial> logcat -v time -s SuperAdsSDK:V <AppTag>:V > <scenario>.log`.
73
72
  2. `launch` app, chờ 5–10s.
74
73
  3. Có dòng `SuperAdsSDK` không? Không có thì Stop.
@@ -76,26 +75,56 @@ Chạy kịch bản `do` / `expect` trên thiết bị: build + cài app, điề
76
75
 
77
76
  **Verify:** file log có dòng của SDK sau khi launch.
78
77
 
79
- ## Phase 3: Chạy kịch bản
80
- - Lấy kịch bản từ [scenarios-sample.md](references/scenarios-sample.md), hoặc viết mới theo [scenario-format.md](references/scenario-format.md).
78
+ ### Phase 3: Chạy kịch bản
79
+ - Lấy kịch bản từ [scenarios-sample.md](examples/scenarios-sample.md), hoặc viết mới theo [scenario-format.md](references/scenario-format.md).
81
80
  - Với mỗi kịch bản: kiểm `needs` với config đang nạp. Không đạt thì `SKIP` kèm lý do.
82
81
  - Thực hiện từng `do`. Sau mỗi `expect`, grep file log hoặc đọc cây UI. Kỳ vọng đầu tiên fail thì dừng kịch bản đó, giữ log, chạy bước trả lại trạng thái.
83
82
 
84
83
  **Verify:** mỗi kịch bản có kết quả và file log riêng.
85
84
 
86
- ## Phase 4: Báo cáo
85
+ ### Phase 4: Báo cáo
87
86
  Bảng `kịch bản | kết quả | bằng chứng | ghi chú`. Kèm serial, model, `versionName`, config đang nạp (`global.version`), đường dẫn các file log.
88
- `FAIL` thì chuyển sang `super-ads-debug` với file log làm đầu vào.
87
+ `FAIL` thì chuyển sang [super-ads-debug](../super-ads-debug/SKILL.md) với file log làm đầu vào.
89
88
 
90
89
  **Verify:** không có dòng `PASS` nào thiếu bằng chứng.
91
90
 
92
- ## Anti-patterns
91
+ ## 🔧 API Reference
92
+ Bước `do` (`launch`, `tap`, `select`, `wait`, `back`, `home`/`resume`, `rotate`, `network`) và `expect` (`log`, `logCount`, `never`, `ui`): [references/scenario-format.md](references/scenario-format.md). Regex theo sự kiện: [references/log-assertions.md](references/log-assertions.md).
93
+
94
+ ## ✅ Best Practices
95
+ - Mỗi kịch bản: bắt đầu từ trạng thái log sạch (`adb logcat -c`, hoặc đánh dấu thời điểm để lấy file `.logads` mới) → `launch` → các bước → lưu file log riêng. Nguồn log ưu tiên là file `.logads`, Logcat là dự phòng ([logging-setup.md](../super-ads-debug/references/logging-setup.md) mục 6).
96
+ - Mỗi kết luận `PASS` / `FAIL` trích dòng log hoặc trạng thái UI làm bằng chứng.
97
+ - Trả lại trạng thái máy đã đổi (mạng, xoay màn) kể cả khi kịch bản fail.
98
+ - Chờ theo dòng log (`expect … within`) thay vì ngủ cố định.
99
+
100
+ ## ❌ Anti-patterns
101
+ - Sửa code, manifest, Gradle, asset config của app. Kể cả "tạm thời".
102
+ - Ghi đè file config của app bằng working config `tmp-*.json` của MCP.
103
+ - Bấm vào ad thật (click) trên bản production, hoặc chạy với unit thật khi chưa được user đồng ý (rủi ro invalid traffic).
104
+ - Báo `PASS` cho kỳ vọng `never` khi không có bằng chứng dương rằng lời gọi đã tới SDK ([log-assertions.md](references/log-assertions.md) mục 4).
105
+ - Chạy `network off` trên emulator/LDPlayer: mất luôn kết nối adb.
93
106
  - Dùng `sleep` cố định thay cho chờ dòng log.
94
107
  - Grep tag Logcat theo `name` (`AdSFl`, `RuleMg`…). Tag luôn là `SuperAdsSDK`, `name` nằm trong message.
95
108
  - Mở màn test bằng `am start` khi Activity không exported.
96
109
  - Bấm nút `Dismiss` của màn test để kiểm dismiss-reload (nút đó gọi `Ads.dismissByPlacement`, không kích reload).
97
110
  - Khớp theo tên lỗi hay tên rule. Dùng `code = N` (tên rule trên bản R8 có thể đã bị đổi).
98
111
 
112
+ ## ⚠️ Common Issues
113
+ **Không có dòng `SuperAdsSDK` sau `launch`.**
114
+ Cause: logger chưa bật ở bản đang cài. Solution: dừng và hỏi user; bật logger là sửa app ([logging-setup.md](../super-ads-debug/references/logging-setup.md) mục 2).
115
+
116
+ **Kịch bản cần config khác với config đang nạp.**
117
+ Cause: config app không thỏa `needs`. Solution: `super-ads-debug-override` nếu có hook; không thì đưa user ba lựa chọn ở "Dừng và hỏi user khi".
118
+
119
+ ## Files created
120
+ Skill này không tạo file nào trong app; nó chỉ ghi file log mỗi kịch bản (`<scenario>.logads` hoặc `<scenario>.log`) ngoài source.
121
+
122
+ ## Files modified
123
+ Skill này không sửa file nào của app. Chỉ khi user chọn phương án sửa config để chạy kịch bản thì mới có thay đổi (đó là sửa app, cần duyệt).
124
+
125
+ ## Verification
126
+ Mỗi phase có dòng **Verify** riêng ở Workflow. Kết thúc: không có dòng `PASS` nào thiếu bằng chứng, và `git status` của app sạch như trước khi chạy.
127
+
99
128
  ## Checklist
100
129
  - [ ] Đã chọn serial, đã cài đúng bản, có `versionName`.
101
130
  - [ ] Logcat có log SDK.
@@ -103,5 +132,25 @@ Bảng `kịch bản | kết quả | bằng chứng | ghi chú`. Kèm serial, mo
103
132
  - [ ] Trạng thái máy đã được trả lại.
104
133
  - [ ] Không file nào của app bị sửa (`git status` của app sạch như trước khi chạy).
105
134
 
135
+ ## 📈 Performance Notes
136
+ > **Not applicable for this skill.**
137
+
138
+ ## 🔒 Security Notes
139
+ > **Not applicable for this skill.**
140
+
141
+ ## 🔄 Migration Guide
142
+ > **Not applicable for this skill.**
143
+
106
144
  ## Output
107
145
  Bảng kết quả theo kịch bản, thông tin thiết bị/bản build/config, đường dẫn log, các kịch bản `SKIP` / `UNKNOWN` kèm lý do, và việc cần làm tiếp (vd chuyển `super-ads-debug`).
146
+
147
+ ## Examples
148
+ Kịch bản hoàn chỉnh S1-S6 (cooldown 101, native inline, collapsible dismiss-reload, App Open guard 108, premium 103, mất mạng 104): [examples/scenarios-sample.md](examples/scenarios-sample.md).
149
+
150
+ ## 📚 References
151
+ - [super-ads-guide](../super-ads-guide/SKILL.md), [super-ads-upgrade](../super-ads-upgrade/SKILL.md)
152
+ - [super-ads-debug](../super-ads-debug/SKILL.md), [super-ads-show-rate](../super-ads-show-rate/SKILL.md), [super-ads-debug-override](../super-ads-debug-override/SKILL.md)
153
+ - [Bật log SDK](../super-ads-debug/references/logging-setup.md)
154
+
155
+ ## 🏷️ Tags
156
+ `superads` `adb` `device-test` `scenario` `logcat` `do-expect`
@@ -1,14 +1,14 @@
1
1
  # Bộ kịch bản mẫu
2
2
 
3
- > Định dạng: [scenario-format.md](scenario-format.md). Regex: [log-assertions.md](log-assertions.md).
4
- > `<P>` là placement **lấy từ config đang được nạp**, không phải tên cố định. Nhãn nút theo app mẫu ([sample-app-notes.md](sample-app-notes.md)); app khác thì thay bằng màn tương đương.
3
+ > Định dạng: [scenario-format.md](../references/scenario-format.md). Regex: [log-assertions.md](../references/log-assertions.md).
4
+ > `<P>` là placement **lấy từ config đang được nạp**, không phải tên cố định. Nhãn nút theo app mẫu ([sample-app-notes.md](../references/sample-app-notes.md)); app khác thì thay bằng màn tương đương.
5
5
  > `SA/` = `super-ads/src/main/java/com/android/fullhd/super_ads/`.
6
6
 
7
7
  Mỗi kịch bản ghi `needs` (điều kiện config). Đọc config trước khi chạy: điều kiện sai thì **bỏ qua kịch bản và ghi lý do**, không chỉnh config cho vừa.
8
8
 
9
9
  ## S1. Inter show rồi bị chặn bởi cooldown (101)
10
10
  - needs: `<P>` fullscreen, `show.timeBetweenMs` của adItem đầu > thời gian thao tác (vd ≥ 10000), mạng bật, không premium.
11
- - App mẫu: `<P>` = `InterChain` (adItem `chain_inter`, `show.timeBetweenMs = 15000`), mở qua Playground. Màn `Interstitial` (`test_inter`) không có cooldown nên kịch bản sẽ `SKIP` ở đó ([sample-app-notes.md](sample-app-notes.md)).
11
+ - App mẫu: `<P>` = `InterChain` (adItem `chain_inter`, `show.timeBetweenMs = 15000`), mở qua Playground. Màn `Interstitial` (`test_inter`) không có cooldown nên kịch bản sẽ `SKIP` ở đó ([sample-app-notes.md](../references/sample-app-notes.md)).
12
12
  - steps:
13
13
  1. `launch` → `tap text:"🎮 Playground (chọn placement)"` → `select id:spinnerCategory value:"INTERSTITIAL_NATIVE_CHAIN"` → `select id:spinnerPlacement value:"<P>"` → `tap id:btnShow`
14
14
  2. `expect log '\[AdSFl\] info=adEventSink Impression: public=<P> ' within 30s`
@@ -23,7 +23,7 @@ Mỗi kịch bản ghi `needs` (điều kiện config). Đọc config trước k
23
23
 
24
24
  ## S3. Collapsible: người dùng bấm đóng → dismiss-reload
25
25
  - needs: `<P>` collapsible có `reload.dismiss.placementID`.
26
- - App mẫu: `<P>` = `native_collapsible_dismiss_reload` hoặc `test_native_collapsible_reload_dismiss`, mở qua Playground (`select id:spinnerCategory value:"NATIVE_COLLAPSIBLE"` → `select id:spinnerPlacement value:"<P>"`). Màn `Native Collapsible` (`test_native_collapsible`) không có `reload.*` ([sample-app-notes.md](sample-app-notes.md)).
26
+ - App mẫu: `<P>` = `native_collapsible_dismiss_reload` hoặc `test_native_collapsible_reload_dismiss`, mở qua Playground (`select id:spinnerCategory value:"NATIVE_COLLAPSIBLE"` → `select id:spinnerPlacement value:"<P>"`). Màn `Native Collapsible` (`test_native_collapsible`) không có `reload.*` ([sample-app-notes.md](../references/sample-app-notes.md)).
27
27
  - steps: `launch` → mở Playground, chọn `<P>` như trên → `tap id:btnShow` → chờ Impression → bấm **nút đóng của chính ad** (không phải nút `Dismiss` của màn test, nút đó gọi `Ads.dismissByPlacement`, `app/src/main/java/com/android/hd/ads2026/test/BaseTestActivity.kt:107-110`) → `expect log '\[ReloadCoord\] info=onSwapCommitted OK: currentPlacementId <P> ->' within 30s`.
28
28
  - Lý do: chỉ đóng do người dùng bấm mới reload; `Ads.dismissByPlacement()` (nút `Dismiss` của màn test) thì không (`SA/show/ReloadCoordinator.kt:225-229`).
29
29
 
@@ -38,7 +38,7 @@ Mỗi kịch bản ghi `needs` (điều kiện config). Đọc config trước k
38
38
  - steps: bật premium → show `<P>` → `expect log '\[RuleMg Block\] action=SHOW .*code = 103'` → `never '...Impression: public=<P> '`.
39
39
 
40
40
  ## S6. Mất mạng (104)
41
- - needs: **máy thật qua USB** (xem `network` trong [scenario-format.md](scenario-format.md)).
41
+ - needs: **máy thật qua USB** (xem `network` trong [scenario-format.md](../references/scenario-format.md)).
42
42
  - steps: `network off` → show `<P>` → `expect log '\[RuleMg Block\] action=SHOW .*code = 104' within 5s` → `network on` (luôn chạy, kể cả khi fail).
43
43
 
44
44
  ## Báo cáo mỗi kịch bản