---
name: reference-interface-request
description: 接口请求规范的详细业务规则（Reference），配合 SKILL.md 使用。包含完整的送礼保底、Bingo、榜单、兑换等深层逻辑。
version: 1.26
dependency:
  doc:
    - skills/testing/data_testing/activity_test_skills/docs/活动信息接口文档.md
    - skills/testing/data_testing/activity_test_skills/docs/管理后台接口文档.md
    - skills/testing/data_testing/activity_test_skills/docs/版本接口文档.md
    - skills/testing/data_testing/activity_test_skills/docs/配置中心接口文档.md
    - skills/testing/data_testing/activity_test_skills/docs/其他接口文档.md
---

# 用例处理流程 - 接口请求详细规范 (Reference)

## 规范化说明

- **规范入口文件**为精简版的 [SKILL.md](./SKILL.md)（侧重于上下文选择和功能调用机制）。
- 本文件为 **Reference（详细规范）**，保留完整业务规则、全量异常判定及各流程约束条件。
- 当执行具体业务流（如送礼保底判定、Bingo自动循环等）时，以本文件的详细逻辑为准。

## 目录导航

- [角色与文档约定](#角色与文档约定)
- [前置：活动信息拉取与校验](#前置活动信息拉取与校验)
- [用户输入信息提取](#用户输入信息提取)
- [测试规则（小礼物 / 礼盒 / 盲盒 / 大礼物）](#测试规则小礼物--礼盒--盲盒--大礼物)
- [Skill 执行方式](#skill-执行方式)
- [环境变量模块](#环境变量模块)
- [Python 脚本约定](#python-脚本约定)
- [接口文档与请求顺序](#接口文档与请求顺序)
- [Bingo 玩法（新增）](#bingo-玩法新增)
- [操作约定（AI 执行时）](#操作约定ai-执行时)
- [简要流程小结](#简要流程小结)

## 术语与优先级（统一）

| 术语 | 约定 |
|------|------|
| 快照 | 指通过 `POST /config/get_key` 解析得到的当前活动配置快照 |
| 快照上下文 | 指当前快照对应的 `act_id`、`region`、默认 `uid`（若存在） |
| 大礼物 | 指配置中心配置的大礼物；不等同于以小搏大触发的大礼物 |
| 参数来源优先级 | 用户显式输入 > 快照上下文默认值 > 向用户确认 |
| 规则优先级 | 接口定义以接口文档为准；流程与判定以本文件为准 |

## 角色与文档约定

| 角色 | 说明 |
|------|------|
| 接口规范来源 | 接口定义以**接口文档**为准，不得臆造路径或参数 |
| 请求流程引擎 | 用例步骤 → 确定接口 → 构造请求 |
| 依赖说明 | 前置 / 主流程 / 校验接口的调用顺序与参数传递 |

**接口类型与域名**（按区服取域名，未指定服默认美服）：

| 接口类型 | 文档 | 域名 |
|----------|------|------|
| 活动接口 | `skills/testing/data_testing/activity_test_skills/docs/活动信息接口文档.md` | 环境变量「活动接口各服域名」 |
| 管理后台接口 | `skills/testing/data_testing/activity_test_skills/docs/管理后台接口文档.md` 或路径 `/activity_admin/` 等 | 环境变量「管理后台各服域名」（区服一致，未指定服默认美服） |
| 版本接口 | `skills/testing/data_testing/activity_test_skills/docs/版本接口文档.md` | 环境变量「版本接口各服域名」（区服与活动/管理后台一致） |
| 配置中心接口 | `skills/testing/data_testing/activity_test_skills/docs/配置中心接口文档.md` | **直接使用该文档中的 Base URL/域名**，不按区服选 |
| 其他接口 | `skills/testing/data_testing/activity_test_skills/docs/其他接口文档.md` | **每个接口的域名单独配置**，见该接口在文档中的「本接口域名」表，按区服对应；空则不可调用 |

**文档与调用关系一览**（本 Skill 涉及的所有文档及主要调用场景）：

| 文档 | 路径 | 主要调用场景 / 典型接口 | 域名约定 |
|------|------|--------------------------|----------|
| 活动信息接口文档 | `skills/testing/data_testing/activity_test_skills/docs/活动信息接口文档.md` | 活动配置快照**之后**的查询与执行：任务组 get_group_list、receive_task_reward；兑换 get_collect_chip、exchange_store/exchange；抽奖 get_lottery_info、do_lottery；碎片 get_collect_chip；盲盒 blind_box_lucky_value/get_info；礼盒保底 get_gift_box_guarantee（**域名用活动接口**）；以小搏大 get_guarantee、get_choose_gift_info | 活动接口各服域名表（按区服） |
| 管理后台接口文档 | `skills/testing/data_testing/activity_test_skills/docs/管理后台接口文档.md` | 礼盒 get_act_gift_box、set_guarantee；任务 incr_condition_value、clear_data；碎片 add_collect_chip；榜单 rank_list、checkout_rank；红包雨 get_state；活动配置检查 activity_config_check；小礼物/道具 get_prop_infos 等 | 管理后台各服域名表（按区服） |
| 版本接口文档 | `skills/testing/data_testing/activity_test_skills/docs/版本接口文档.md` | 送礼 send_gift_public（红包雨不可用时的 fallback） | 版本接口各服域名表（按区服） |
| 配置中心接口文档 | `skills/testing/data_testing/activity_test_skills/docs/配置中心接口文档.md` | **前置快照** `POST /config/get_key`（region、namespace=activity、key=act_id、app_id=1）；**送礼前校验** `POST /assets/get_open_list`（礼物 numbers、gift_type、region） | 文档内 Base URL，不按区服 |
| 其他接口文档 | `skills/testing/data_testing/activity_test_skills/docs/其他接口文档.md` | 红包雨送礼 `POST /voice_room/send_gift`；get_user_info 等（若文档收录） | 各接口单独「本接口域名」表，按区服；空则不可调用 |
| 使用大纲 | `skills/testing/data_testing/activity_test_skills/README.md` | **调用后统计**：接口调用成功（code 200）后，将方法+路径+成功参数按接口文档分类填写至「接口使用情况统计」对应小节；不重复填写已存在记录；分类与上述五份接口文档对应（见 README 内小节标题） | — |
| 用例 Skill / 用例文件 | [testcase.md](../testcase.md)、`./【埋点文档】xxx.md` | **步骤适配**：用户要求按用例做接口适配时，读取用例步骤，在活动/管理后台/版本/配置中心/其他接口文档中匹配接口并绑定方法+路径+参数 | — |

**文档结构说明**：各接口文档一级标题为模块名，二级标题为 `## METHOD 接口名称`，后接方法+路径与 `### 请求参数` 表；构造请求时从文档提取方法、路径、参数位置（query/body）、参数名与类型，**键名大小写与成功示例以文档为准**。

---

## 前置：活动信息拉取与校验

**每次用户输入 act_id 时**：先在快照中查是否**已存在该 act_id** 的配置；**若已存在则不需要初始化**（不调用 get_key）；**若不存在则初始化**：调用配置中心 **`POST /config/get_key`**（参数见配置中心接口文档：region=地区缩写、namespace=activity、key=act_id、app_id=1）获取该活动的**完整配置**，将返回的 **result.value**（JSON 字符串）解析后整理为**活动配置快照**；**并删除之前的快照，仅保留当前 act_id 的快照**（同一会话中只保留一份快照，对应当前 act_id）。供后续所有测试操作优先使用。

**快照上下文（用于未指定 act_id/uid 时的入参）**：生成或更新快照时，记录**当前快照对应的 act_id** 以及本次 get_key 使用的 **region**（区服）；若用户在本轮或前置步骤中提供过 **uid**，一并记录为**默认 uid**。后续任意接口调用**未显式指定 act_id、uid 或区服时**，**按快照上下文入参**：优先使用上述 act_id、uid、region 作为该次请求的入参（详见下方「未指定 act_id、uid 时的入参约定（全局）」）；仅当快照上下文中从未有过 uid 且当前接口必须传 uid 时，再向用户确认。

**活动配置快照**（从 get_key 的 value 解析）可包含但不限于：
- **gift_list**：活动配置的礼物 id 列表（可能混合多种类型，需结合下方区分规则使用）
- **special_info**：small_gift_id（小礼物）、gift_box（礼盒）、rank_gift_list 等
- **extra_gifts**：以小搏大配置，含 gift_list（小礼物 id）、random_list（**以小搏大触发用**的 gift_id、guarantee；与本 Skill 所称「大礼物」区分，见下方四类礼物定义）
- **lottery**：奖池数组，每项含 type、cost_chip_meta_list（chip_id、chip_num/次）
- **send_gift_hooker_v2**：礼物 id 与玩法类型（small_gift、gift_box、blind_gift、big_gift）的映射
- **任务、兑换、collect_chip** 等其余配置
- **兑换**：快照中可能含 **exchange_store**、**exchange_list**、**store_list** 或 special_info 下与兑换商店相关的配置；从中可解析 **store_name**、**exchange_type**（兑换类型/项 ID）、以及兑换所需道具（如 **chip_id**）及数量（**chip_num** 或 cost 等）。不同活动配置结构可能不同，以实际 value 为准。
- **榜单**：快照中可能含榜单相关配置（如 **rank_list**、**rank_type** 或 special_info 下与排行榜相关的字段）；从中可解析当前活动**已配置的榜单类型**（如 rank_type 取值或榜单标识列表），用于**榜单查询、榜单结算前**校验「当前榜单是否存在」。

**快照中四类礼物的区分**（送礼、测试保底等须按类型取 gift_id 时，按以下优先级从快照识别；若某类在快照中无则再调下表对应查询接口）。**约定**：本 Skill 中**大礼物**指**配置中心配置的大礼物**，与「以小搏大」玩法中触发的大礼物（extra_gifts[].random_list[]、get_guarantee 的 key）区分，后者仅用于小礼物保底流程。

| 类型 | 快照中的来源（优先级从高到低） | 说明 |
|------|-------------------------------|------|
| **小礼物** | ① special_info.small_gift_id ② extra_gifts[].gift_list（如首项）③ send_gift_hooker_v2 中类型为 **small_gift** 的 gift_id ④ gift_list 中结合 hooker 或业务含义取 | 以小搏大里送的那款；红包雨 trigger_gift_infos 未返回时也可从本类取 |
| **礼盒** | ① special_info.gift_box ② send_gift_hooker_v2 中类型为 **gift_box** 的 gift_id ③ 管理后台 get_act_gift_box | 开盒玩法，有礼盒保底接口 |
| **盲盒** | ① send_gift_hooker_v2 中类型为 **blind_gift** 的 gift_id ② 活动/管理后台盲盒查询接口（如 get_act_blind_box、blind_box_lucky_value/get_info） | 盲盒玩法，有盲盒保底等 |
| **大礼物** | ① send_gift_hooker_v2 中类型为 **big_gift** 的 gift_id ② 活动 get_choose_gift_info（或配置中心/活动侧可识别为大礼物的配置） | **指配置中心配置的大礼物**，并非以小搏大中的大礼物；以小搏大触发用的大礼物见「小礼物保底」流程（get_guarantee 的 key、extra_gifts[].random_list[]），不在此类取。 |

同一活动可能只配置其中部分类型（如无礼盒则 special_info.gift_box 为空）；取不到时再按「送礼前查询活动礼物 ID」表调接口。

**后续执行测试操作时**：**优先从活动配置快照中获取**所需信息（如小礼物 gift_id、礼盒 id、奖池 Type、消耗 chip_id/chip_num 等）；**若快照中获取不到**或字段缺失，再通过其他渠道获取（如 get_prop_infos、get_act_gift_box、get_lottery_info、get_open_list 等）。快照按**当前 act_id** 唯一保留一份；用户输入新的 act_id 且快照中不存在该 act_id 时，按上段执行 get_key 并**用新快照替换旧快照**。

可选补充（快照不足以做校验或需最新状态时）：活动配置检查、查询任务列表、查询任务明细、道具检查等（见管理后台/活动接口文档），按需调用。

---

## 用户输入信息提取

从用户输入中提取并映射为接口参数：

| 用户表述 | 参数 |
|----------|------|
| 用户id=123 / 用户ID=123 | `uid=123` |
| 活动id=456 / 活动ID=456 | `act_id=456` |
| 任务id=1 / 任务ID=1 | `task_id=1` |
| 结算日榜 / 日榜结算日期=20240205 / 指定日期 | **日榜结算**时：未指定日期则默认**当日日期**；指定了则用**指定日期**；格式 **YYYY-MM-DD**，通过管理后台 checkout_rank 的 **datetime** 参数传入。 |

**送礼场景**：用户要求送小礼物、礼盒、盲盒、大礼物时，必须从上下文中取得 **act_id**，先按「送礼前查询活动礼物 ID」查得 **gift_id**，再构造送礼请求。**未指定 act_id、uid 时**按下方「未指定 act_id、uid 时的入参约定（全局）」以快照上下文入参。

**未指定 act_id、uid 时的入参约定（全局）**：调用任意接口时，若**未显式指定 act_id 或 uid**，**按生成快照时的数据入参**——即使用**当前快照对应的 act_id** 作为 act_id；使用**快照上下文中记录的 uid**（若存在）作为 uid；使用**生成快照时所用的 region** 作为区服以取域名与 get_key 等。仅当**尚无快照**（未执行过 get_key）或**快照上下文中从未有过 uid** 且当前接口**必须传 uid** 时，再向用户确认 act_id 或 uid。本约定适用于所有需传 act_id/uid 的接口（任务、兑换、抽奖、送礼、榜单、碎片等）。

未指定其他参数时由调用方或环境配置提供默认值。

**获取当前用户 rid**：需要**当前用户（或指定用户）所在语音房 rid** 时（如红包雨送礼、voice_room/send_gift 等），调用管理后台 **`POST /censor/get_user_info`**（见 `skills/testing/data_testing/activity_test_skills/docs/管理后台接口文档.md`），Body 传 **uid**（**整型**，当前用户 uid；未指定时按快照上下文 uid）、**lang** 可选；从返回 **result.rid** 或 **result.vip_room_list** 取 rid——**result.rid** 为当前房间 id（整型），**result.vip_room_list** 可能为字符串（如 `"10121355"` 或逗号分隔多房间），取第一个或按需解析。域名用**管理后台各服**。若 get_user_info 无可用 rid，再尝试活动接口 `POST /activity_v2/h5_send_gift/get_random_rid`（act_id、uid）；仍无则 rid 传 0 或 1。

---

## 测试规则（小礼物 / 礼盒 / 盲盒 / 大礼物）

当用户表示要**测试**小礼物、礼盒、盲盒或大礼物时，按以下规则执行，并**根据用户想测试的内容自动触发对应流程**。

1. **先查询对应类型的礼物 ID**
   - 根据用户想测试的类型（小礼物 / 礼盒 / 盲盒 / 大礼物），使用下方「送礼前查询活动礼物 ID」表中**该类型对应的查询接口**，结合用户上下文中的 **act_id**（及 uid 等）查询得到 **gift_id**。
   - 礼盒：`POST /activity_admin/gift_box/get_act_gift_box`（Body 传 `ActId`），从返回列表中取 gift_id。
   - 盲盒：活动端 `POST /activity_v2/blind_box_lucky_value/get_info` 等，从返回中取盲盒 gift_id。
   - 大礼物：`POST /activity_v2/extra_gift/get_choose_gift_info`，从返回中取大礼物 gift_id。
   - 小礼物 / 普通礼物：`GET /analysis_api/activity/get_prop_infos` 或活动内礼物配置，确定 gift_id。

2. **按测试意图自动触发后续流程**
   - **仅需礼物 ID**：若用户只要求查 ID 或“有哪些礼盒/盲盒”等，则返回查询到的 gift_id（及必要说明）即可。
   - **测试送礼**：若用户要测试送礼或“测试礼盒/小礼物等”且涉及送礼，则在使用上述 gift_id 的基础上，再按「送礼前必须查询礼物信息并校验」执行校验，通过后**优先调用红包雨送礼接口** `POST /voice_room/send_gift`（需先根据用户 ID 查 rid），若该接口无法执行再调用版本接口 `POST /game_api/send_gift_public`，并返回结果摘要。
   - **测试礼盒保底**：用户说「测试礼盒保底」时，**须执行完整流程**：① 取得礼盒 **gift_id**（`POST /activity_admin/gift_box/get_act_gift_box`）；② **礼盒保底查询** `POST /activity_v2/common/get_gift_box_guarantee`（**域名使用活动接口**），从返回 result.data[reward_id] 取 **N = guarantee**；③ **修改保底值** `POST /activity_admin/gift_box/set_guarantee` 传 **val = N - 1**（reward_id 与返回 key 一致）；④ 校验礼盒并读 numbers；⑤ **送 1 份礼盒**给自己触发保底；未触发则再次查询并按需继续送。**以上接口参数见活动信息接口文档、管理后台接口文档、版本接口文档。**
   - **测试礼盒保底等（仅设置保底）**：若用户仅要求「设置礼盒保底」、不要求送满触发，则在取得礼盒 gift_id 与 **reward_id**（从活动配置或接口返回获取）后，调用管理后台 `POST /activity_admin/gift_box/set_guarantee`，参数见管理后台接口文档。

**示例（测试小礼物保底）**：① `POST /activity_v2/extra_gift/get_guarantee`，根据返回形态得 need_times（见下方「get_guarantee 返回形态」）；② 确定小礼物 gift_id；③ 配置中心校验礼物并读取 **numbers**；④ **按最优数量组合**凑满 need_times 送小礼物；⑤ 送满后**再次 get_guarantee**；⑥ **确认保底触发**：**送礼流程走完后，need_times=0 时才算已经触发保底**；若接口在触发后直接进入新一轮，返回 **cur_times=0 且 need_times=保底总数**（如 guarantee 值）时，同样视为已触发保底。**trigger_map 增加只表示爆出了以小搏大中的大礼物**，可能是随机出的也可能是保底出的，**不能单独作为保底已触发的依据**。若送满后 need_times 未为 0 且非「cur_times=0 且 need_times=保底总数」（无论 trigger_map 是否增加），说明可能是概率出了以小搏大中的大礼物、计数已重置，按当前 need_times 回到步骤 ④ 继续送礼，重复 ⑤⑥ 直至**某次送满后 need_times=0 或 cur_times=0 且 need_times=保底总数**，即确认保底触发。**接口参数见活动信息接口文档、配置中心接口文档、版本接口文档。**

**get_guarantee 返回形态**（小礼物保底）：result 的 key 为**以小搏大触发的大礼物** gift_id（即 extra_gifts[].random_list[] 中该项，非本 Skill 所称「大礼物」），value 可能为两种形态，需区分后得到 need_times 与 cur_times。**形态一**：value 为**对象**，含 guarantee、cur_times、need_times、trigger_map → 直接取 **need_times** 为还需送件数。**形态二**：value 为**数字**（如 `{"1209820":165}`），表示**当前轮已送小礼物件数**（即 cur_times）→ **need_times = 保底总数(guarantee) − 该数**；保底总数从活动配置快照 **extra_gifts[].random_list[]** 中与该**以小搏大触发的大礼物** gift_id（result 的 key）对应的项取 **guarantee** 字段；若快照中无则从同接口其他返回或活动配置获取。两种形态下，送满 need_times 后再次 get_guarantee，**确认保底触发**：**need_times=0** 即已触发；或返回 **cur_times=0 且 need_times=保底总数**（接口触发后直接进入新一轮）时同样视为已触发保底。

**保底计数说明**：小礼物保底按**礼物件数**（每次请求的 `number` 之和）计数，不是按请求次数。送满 need_times 件后可能触发**以小搏大中的大礼物**（保底或随机）；送后再查 get_guarantee 时，**need_times=0** 可认为**已经触发保底**；或返回 **cur_times=0 且 need_times=保底总数**（接口触发后直接进入新一轮）时同样视为已触发保底。**trigger_map 增加只表示爆出了以小搏大中的大礼物**，可能是随机也可能是保底，**不能单独作为保底触发的依据**。若送满 need_times 后 need_times 未为 0 且非「cur_times=0 且 need_times=保底总数」：表示在达到保底前已因**概率出了以小搏大中的大礼物**，保底计数被重置，当前批中部分件数计入下一轮；此时需**根据当前 need_times 继续送礼**，直至**某次送满后 need_times=0 或 cur_times=0 且 need_times=保底总数**，即确认保底触发。

**测试小礼物保底（执行检查与常见错误）**：执行或实现「测试小礼物保底」时须符合下列规则，否则视为未按设定规则测试：

| 检查项 | 规则 | 常见错误 |
|--------|------|----------|
| get_guarantee 请求方式 | **必须**使用 **form 表单**（Content-Type: application/x-www-form-urlencoded），参数 act_id、uid、id（一般为 1）；活动信息接口文档注明使用 JSON 时部分环境可能返回 500 | 使用 JSON 提交导致 500 或参数错误 |
| 小礼物 gift_id 来源 | **优先从活动配置快照**取：special_info.small_gift_id 或 extra_gifts[].gift_list（如首项）；快照无再调 get_prop_infos | 未从快照取、或快照解析逻辑错误（如 and/or 混用）导致 gift_id 为空或取错 |
| 最优数量组合 | **优先用允许的单次最大数量**：每笔在 numbers 中选 **≤ 剩余件数的最大允许值**（如 numbers=[99,66,10,3,1]、剩余 100 件则先送 99 再送 1），再以其余允许数量凑满，减少请求次数 | 误用**最小值**凑单（如每次送 1 件）导致请求次数过多、未按全局送礼原则 |
| rid 与送礼接口 | 送礼前**必须先**根据用户 ID 查 rid（get_user_info 取 result.rid 或 vip_room_list）；**优先** voice_room/send_gift，无法执行再 fallback send_gift_public | 未查 rid 直接传 0/1；或未优先使用红包雨送礼接口 |
| 送满后循环直至触发 | 送满 need_times 后**必须再次 get_guarantee**；若 need_times≠0 且非「cur_times=0 且 need_times=保底总数」，**必须按当前 need_times 继续送礼**并重复「再次 get_guarantee → 判定」，直至 need_times=0 或 cur_times=0 且 need_times=保底总数 | 只送一轮、再查一次即结束，未在未触发时**继续送礼并循环** |
| 保底触发判定 | 仅当 **need_times=0** 或 **cur_times=0 且 need_times=保底总数** 时视为已触发保底；**trigger_map 增加不能单独作为已触发依据** | 仅凭 trigger_map 增加即判定已触发 |

实现时（含脚本或自动化）：须先查快照、get_guarantee 用 form、小礼物从快照取、numbers 按**单次最大允许数量**组合、rid 先查再送、送满后循环再查直至上述判定成立。

**示例（测试礼盒保底）**：① get_act_gift_box 得 gift_id；② get_gift_box_guarantee（**活动接口域名**）得 N = result.data[reward_id].guarantee；③ set_guarantee 传 val = N - 1（reward_id 与返回 key 一致）；④ 校验礼盒并读 numbers；⑤ 送 1 份礼盒给自己触发保底；未触发则再次查询并按需继续送。**接口参数见活动信息接口文档、管理后台接口文档、版本接口文档。**

**恋恋魔方礼盒保底机制（特殊类型）**：部分活动的礼盒采用"恋恋魔方"机制，与传统礼盒保底不同。该机制通过送礼返回中的 **combo_desc**（如"距离6星奖励N次"）显示计数器状态，**无需调用 get_gift_box_guarantee 查询**（该接口返回空或无保底配置）。机制特点：① **双重触发机制**：随机触发（小概率，约0.1-0.3%）+ 保底触发（计数器到1时100%）；② **计数器递减**：每送1个礼盒，计数器-1；③ **保底触发点**：计数器=1时，下一次送礼**必定触发稀有奖励**（如六星）；④ **触发后重置**：触发稀有奖励后，计数器立即重置到初始值（如900-913）；⑤ **永不显示0**：计数器从1→0的瞬间触发并重置，对外永远看不到0。

**恋恋魔方保底验证方式**（测试该机制时按以下步骤）：① **识别机制**：送礼返回的 combo_desc 含"距离N星奖励X次"字样，且 get_gift_box_guarantee 返回空或无保底配置，判定为恋恋魔方机制；② **记录初始计数器**：送1个礼盒，从返回 Result.combo_desc 提取计数器值（如"距离6星奖励913次"→913）；③ **验证递减规律**：送N个礼盒，确认计数器精确递减N（未触发稀有奖励时）；④ **验证保底触发**：持续送礼至计数器=2 → 送1个到计数器=1（观察未触发稀有奖励）→ 再送1个（**必定触发稀有奖励且计数器重置到初始值**）；⑤ **验证随机触发**：在计数器>1时若触发稀有奖励，计数器同样重置；⑥ **确认重置值**：多次触发后统计重置值范围（通常固定或在小范围波动，如900-913）。**验证要点**：计数器=1时送礼是关键验证点，必定触发且立即重置；永远看不到计数器=0的状态；触发与否可从返回 desc 或 animation_index 判断（如"触发六星"、animation_index变化）。

**红包雨测试方式（触发下一阶段）**：用户要求「测试红包雨」或「触发下一阶段红包雨」时，按以下三步执行。① **语音房 rid**：**须根据用户 ID 查询**（如调用 get_user_info 等接口取用户房间列表 vip_room_list，得到该用户所在语音房 rid）；不可随意传 0 或 1。② **查询红包雨所需小礼物**：调用管理后台 `POST /activity_admin/red_packet/get_state`（Body 传 **ActId、Uid、rid**，键名大写、值为数字；**rid 使用上步根据用户 ID 查到的房间 id**，get_state 的 rid 仅传房间 id **后六位**，如 10268286→268286），从返回 **result.trigger_gift_infos** 中取小礼物 **id**（即 gift_id）；若该接口未返回 trigger_gift_infos，则**优先从活动配置快照 special_info.small_gift_id** 取。③ **查询红包雨下一阶段所需值**：同上接口 get_state，从返回 **result.next_value**（下一阶段所需累计值）、**result.current_val**（当前已累计值）获取实际情况；**红包雨本次送礼数量 = next_value**（就按 next_value 的数量送，**直接送 next_value 件**），**不做 next_value − current_val 的减法**（该减法不是红包雨逻辑）。按全局送礼最优方式调用红包雨送礼（共送 **next_value** 件），送完后再次 get_state，直至状态已进入下一阶段（next_value 更新）。④ **按礼物送礼原则找最优方式并调用红包雨送礼**：配置中心 `POST /assets/get_open_list` 查询该 gift_id 的 **numbers**；按**全局送礼原则**（见「送礼原则（全局）」）的**最优数量组合**拆成多笔；**本阶段共送 next_value 件**（不做 next_value − current_val）；每笔调用 `POST /voice_room/send_gift`（**域名使用** `skills/testing/data_testing/activity_test_skills/docs/其他接口文档.md` 中该接口「本接口域名」表按区服取），参数 send_uid、recv_uid、gift_id、**gift_number**（每笔数量）、**rid**（同上，须为根据用户 ID 查到的房间 id）、game_type 等见其他接口文档。按**next_value** 件送满后，再次 get_state 确认是否已进入下一阶段；若未进入则继续按最新 next_value（**直接送 next_value 件**）送礼直至触发。**以上接口参数见管理后台接口文档、配置中心接口文档、其他接口文档。**

未提供 act_id 或 uid 时，**按生成快照时的数据入参**（见「未指定 act_id、uid 时的入参约定（全局）」）；无快照或快照无 uid 且接口必传 uid 时再向用户确认。

---

## Skill 执行方式

按用户意图二选一：**用户主动给出步骤** 或 **基于用例文件做步骤适配**。

### 方式一：用户主动调用

用户给出步骤（如「先查任务组信息，再领取任务奖励」），要求按步骤调接口并展示结果。

1. **解析步骤** → 确定每步业务意图（查配置、领奖、兑换等）。
2. **查找接口** → 在对应接口文档中按模块/接口名/关键词获取方法、路径、请求参数。
3. **构造并发送请求** → 按环境变量取域名，拼接 URL，按文档构造请求并调用。
4. **处理返回值** → 提取 `code`/`msg`/`result` 及业务字段，整理为关键信息（状态、数据、错误原因），结构化展示；避免直接贴原始 JSON。

**测试类流程（含小礼物保底、礼盒保底等所有按步骤的测试）**：**按本 Skill 流程直接调用接口**执行——依次请求各接口、传递上一步结果到下一步、汇总返回；**非必要不编写脚本**，即**不生成、不新增**测试脚本文件。仅当用户**明确要求**「生成脚本」或「写个 Python 跑」时再生成或修改脚本。

**示例（完成任务并领取奖励）**：先查任务完成状态（任务组/任务信息接口）→ 若已完成未领取则直接领奖；若已领取则先清空状态（若有接口）再重做 → 再按业务完成任务并领奖。多阶段任务先遍历各阶段完成情况，再按 2a/2b 分支执行。

### 方式二：基于用例文件的步骤适配

依赖 [testcase.md](../testcase.md) 生成的用例文件（如 `./【埋点文档】xxx.md`）。用户要求「根据 xxx 用例步骤做接口适配」时：

1. **读取用例文件** → 解析测试步骤（操作描述、预期）。
2. **提取步骤信息** → 得到每步意图（如领取任务奖励、查询任务组、兑换奖励）。
3. **接口文档适配** → 在活动/管理后台/版本/配置中心/其他接口文档中匹配接口，为每步绑定「方法 + 路径 + 参数」；找不到则标记**适配不上**。
4. **返回结果** → 列出步骤 ↔ 接口对应；适配不上的步骤明确标出，不强行匹配。

---

## 环境变量模块

用例执行/接口请求时，按**目标环境**与**目标服**选择域名。当前**仅支持测试环境**；正式环境可预留命名，但不得用于请求构造与用例执行。

| 环境 | 说明 | 支持 |
|------|------|------|
| 测试环境 | 联调、用例执行、自动化测试 | ✅ |
| 正式环境 | 生产环境 | ❌ |

**使用方式**

- **域名严格按照文档要求**：取域名时**必须**按下列文档约定执行，**不得**根据区服名称自行推断、拼写或使用未在文档中列出的域名。① **活动 / 管理后台 / 版本接口**：**必须**从本 Skill 下方「管理后台 / 活动接口 / 版本接口 - 测试环境各服域名」表中按目标区服查得域名后使用。② **其他接口**（如 voice_room/send_gift）：**必须**从 `skills/testing/data_testing/activity_test_skills/docs/其他接口文档.md` 中该接口的「本接口域名」表按区服查得后使用。③ **配置中心**：使用 `skills/testing/data_testing/activity_test_skills/docs/配置中心接口文档.md` 中的 Base URL。凡未在对应文档/表中列出的区服或域名为空/待补充时，**不调用该接口**并说明原因。
- **活动 / 管理后台 / 版本接口**：按下表（本模块各服域名）按目标服选行，**域名 + 路径**得完整 URL；未指定服时默认**美服**。
- **配置中心 / 其他接口**：不查下表。配置中心使用 `skills/testing/data_testing/activity_test_skills/docs/配置中心接口文档.md` 中的 Base URL。**其他接口**：**每个接口的域名单独配置**，使用该接口在 `skills/testing/data_testing/activity_test_skills/docs/其他接口文档.md` 中的「本接口域名」表，按目标区服取该接口对应域名；若该区服域名为空或「待补充」则不可调用，需中断并返回原因。

**区服域名为空时**：若**当前要调用的接口**在对应文档中，目标区服的**该接口域名为空或未配置**（如其他接口文档中该接口下「本接口域名」表该服为「待补充」），则**不调用该接口**，**中断流程**并返回原因（如：「区服 [服名] 的 [接口名/路径] 域名未配置，无法调用」）。

### 管理后台 - 测试环境各服域名

（管理端接口：`skills/testing/data_testing/activity_test_skills/docs/管理后台接口文档.md` 或路径 `/activity_admin/` 等）

| 序号 | 服名 | 域名（测试环境） |
|------|------|------------------|
| 1 | 美服 | `https://admin-dev-api-sv.weplayapp.com` |
| 2 | 西语服 | `https://admin-dev-api-va.weplayapp.com` |
| 3 | 葡语服 | `https://admin-dev-api-br.weplayapp.com` |
| 4 | 法语服 | `https://admin-dev-api-par.weplayapp.com` |
| 5 | 俄语服 | `https://admin-dev-api-rus.weplayapp.com` |
| 6 | 德语服 | `https://admin-dev-api-de.weplayapp.com` |
| 7 | 意语服 | `https://admin-dev-api-it.weplayapp.com` |
| 8 | 华语服 | `https://admin-dev-api-sgp.weplayapp.com` |
| 9 | 泰服 | `https://admin-dev-api-bkk.weplayapp.com` |
| 10 | 马尼服 | `https://admin-dev-api-mas.weplayapp.com` |
| 11 | 菲律宾服 | `https://admin-dev-api-phl.weplayapp.com` |
| 12 | 越南服 | `https://admin-dev-api-vnm.wejoysg.com` |
| 13 | 日服 | `https://admin-dev-api-tky.weplayapp.com` |
| 14 | 韩服 | `https://admin-dev-api-sel.weplayapp.com` |
| 15 | 阿语服 | `https://admin-dev-api-fra.weplayapp.com` |
| 16 | 土语服 | `https://admin-dev-api-tur.weplayapp.com` |
| 17 | 印度服 | `https://admin-dev-api-in.weplayapp.com` |
| 18 | 巴基斯坦服 | `https://admin-dev-api-pk.weplayapp.com` |
| 19 | JK服 | `https://admin-dev-api-ar.jackarooapp.com` |
| 20 | 会玩 | `https://wespy-admin-api-dev.wepieoa.com` |

### 活动接口 - 测试环境各服域名

（活动相关接口：`skills/testing/data_testing/activity_test_skills/docs/活动信息接口文档.md`）

| 序号 | 服名 | 域名（测试环境） |
|------|------|------------------|
| 1 | 美服 | `https://activity-dev-sv.weplayapp.com` |
| 2 | 西语服 | `https://activity-dev-va.weplayapp.com` |
| 3 | 葡语服 | `https://activity-dev-br.weplayapp.com` |
| 4 | 法语服 | `https://activity-dev-par.weplayapp.com` |
| 5 | 俄语服 | `https://activity-dev-rus.weplayapp.com` |
| 6 | 德语服 | `https://activity-dev-de.weplayapp.com` |
| 7 | 意语服 | `https://activity-dev-it.weplayapp.com` |
| 8 | 华语服 | `https://activity-dev-sgp.weplayapp.com` |
| 9 | 泰服 | `https://activity-dev-bkk.weplayapp.com` |
| 10 | 马尼服 | `https://activity-dev-mas.weplayapp.com` |
| 11 | 菲律宾服 | `https://activity-dev-phl.weplayapp.com` |
| 12 | 越南服 | `https://activity-dev-vnm.wejoysg.com` |
| 13 | 日服 | `https://activity-dev-tky.weplayapp.com` |
| 14 | 韩服 | `https://activity-dev-sel.weplayapp.com` |
| 15 | 阿语服 | `https://activity-dev-fra.weplayapp.com` |
| 16 | 土语服 | `https://activity-dev-tur.weplayapp.com` |
| 17 | 印度服 | `https://activity-dev-in.weplayapp.com` |
| 18 | 巴基斯坦服 | `https://activity-dev-pk.weplayapp.com` |
| 19 | JK服 | `https://activity-dev-ar.jackarooapp.com` |
| 20 | 会玩 | `https://activity-api-dev.afunapp.com` |

### 版本接口 - 测试环境各服域名

（版本/游戏相关接口：`skills/testing/data_testing/activity_test_skills/docs/版本接口文档.md`，如 `/game_api/` 等）

| 序号 | 服名 | 域名（测试环境） |
|------|------|------------------|
| 1 | 美服 | `https://api-dev-sv.weplayapp.com` |
| 2 | 西语服 | `https://api-dev-va.weplayapp.com` |
| 3 | 葡语服 | `https://api-dev-br.weplayapp.com` |
| 4 | 法语服 | `https://api-dev-par.weplayapp.com` |
| 5 | 俄语服 | `https://api-dev-rus.weplayapp.com` |
| 6 | 德语服 | `https://api-dev-de.weplayapp.com` |
| 7 | 意语服 | `https://api-dev-it.weplayapp.com` |
| 8 | 华语服 | `https://api-dev-sgp.weplayapp.com` |
| 9 | 泰服 | `https://api-dev-bkk.weplayapp.com` |
| 10 | 马尼服 | `https://api-dev-mas.weplayapp.com` |
| 11 | 菲律宾服 | `https://api-dev-phl.weplayapp.com` |
| 12 | 越南服 | `https://api-dev-vnm.wejoysg.com` |
| 13 | 日服 | `https://api-dev-tky.weplayapp.com` |
| 14 | 韩服 | `https://api-dev-sel.weplayapp.com` |
| 15 | 阿语服 | `https://api-dev-fra.weplayapp.com` |
| 16 | 土语服 | `https://api-dev-tur.weplayapp.com` |
| 17 | 印度服 | `https://api-dev-in.weplayapp.com` |
| 18 | 巴基斯坦服 | `https://api-dev-pk.weplayapp.com` |
| 19 | JK服 | `https://api-dev-ar.jackarooapp.com` |

---

## Python 脚本约定

**约束**：**非必要不添加新的脚本文件或 Python 脚本**。测试与接口执行优先**直接调用各接口**、按步骤传递结果；仅当用户**明确要求**生成/运行脚本或确有自动化、联调等需要时，再在下方目录创建或修改脚本。

若需用 Python 发起请求（自动化执行、联调等），在**`skills/testing/data_testing/activity_test_skills/scripts/` 目录**创建脚本；单脚本场景可集中使用 `request.py`，多脚本时按功能拆分并遵守下列约定。

**多脚本时的命名与创建**
- 在生成新脚本前，**先检查 `skills/testing/data_testing/activity_test_skills/scripts/` 目录**是否已有同名或功能重叠的文件，避免重复命名；若存在同名文件，应改用更具区分度的文件名或复用现有脚本并扩展功能。
- 脚本文件名应能体现用途（如 `request.py`、`qrcode_pdf.py`），便于识别与维护。所有新生成的脚本必须放在 `skills/testing/data_testing/activity_test_skills/scripts/` 目录下。

**脚本内功能与备注**
- 生成或修改脚本时，**必须在脚本内标注当前脚本的功能说明与备注**：在文件头部使用模块级 docstring 说明**功能**（本脚本用于做什么）、**入参/用法**（如命令行参数或调用方式）、**依赖与注意点**（可选）；关键逻辑处可加简短行内注释。
- 示例：文件开头包含 `""" 功能：xxx。用法：xxx。备注：xxx。"""` 或等价多行说明。

| 约定项 | 说明 |
|--------|------|
| 文件路径 | `skills/testing/data_testing/activity_test_skills/scripts/` 目录下；多脚本时按功能命名，避免与现有文件重名 |
| 用途 | 封装活动/管理后台/版本/配置中心/其他接口的请求构造与发送；活动/管理后台/版本按本 Skill 各服域名表取域名，配置中心/其他接口使用对应接口文档中的 Base URL |
| 运行环境 | 使用**项目虚拟环境**内的 Python（如 `source .venv/bin/activate` 后 `python skills/testing/data_testing/activity_test_skills/scripts/request.py`，或 `.venv/bin/python skills/testing/data_testing/activity_test_skills/scripts/request.py`），避免使用系统全局 Python |
| 功能与备注 | 脚本顶部须有**功能说明**（本脚本用途）及**备注**（用法、依赖或注意点）；生成前检查 `skills/testing/data_testing/activity_test_skills/scripts/` 目录是否重复命名 |

---

## 接口文档与请求顺序

**参数以接口文档为准**：所有接口的**请求方法、路径、Body/Query 参数**（含键名大小写、类型、成功示例等）均在对应接口文档中整理；本 Skill 仅规定**调用顺序与业务规则**，构造请求时以各接口文档为准。文档与调用对应关系见上文「文档与调用关系一览」。

**文档结构**：与上文「文档结构说明」一致（一级标题模块、二级标题 `## METHOD 接口名称`、`### 请求参数` 表），构造请求时据此提取方法、路径、参数位置与参数类型。

**请求顺序**：按 **前置 → 主流程 → 校验** 组织。前置获取活动/任务/配置等上下文；主流程对应用例核心操作（领奖、兑换、抽奖等）；校验用于断言或后续步骤。先查后操：写操作前如需当前状态，先调查询/配置接口。前置返回的 `act_id`、`task_id`、`group_id` 等可作为后续参数。

**步骤 → 接口映射**：

| 步骤关键词 | 建议查找 |
|------------|----------|
| 领取、奖励 | 任务奖励、礼包领取；reward、receive |
| 任务、进度 | 任务组、任务信息、领取任务奖励；**测试任务完成**时见下方「测试任务完成步骤」 |
| 兑换 | 兑换商店：兑换奖励、查询兑换、批量兑换 |
| 礼包、购买 | 礼包、不放回礼包、连锁礼包 |
| 送礼、送礼物、小礼物、礼盒、盲盒、大礼物 | **均按全局送礼原则**：先查活动礼物 ID（见下表）→ 送礼前必须查询礼物信息并校验（含 numbers）→ **按最优数量组合**→ **优先调红包雨送礼接口** `POST /voice_room/send_gift`（需先根据用户 ID 查 rid），若无法执行再调版本接口 `POST /game_api/send_gift_public`；**语音房/红包雨场景下 rid 须根据用户 ID 查询**（如 get_user_info 取 vip_room_list），再传 get_state 与 voice_room/send_gift；未提供 rid 时先查用户信息取 vip_room_list，无则 rid 传 0 或 1 |
| 投票、投稿 | 投票、直接投稿、搜索作品 |
| 排行榜、榜单查询、榜单结算 | 见下方「榜单查询与结算（全局）」：先查快照是否存在当前榜单，存在则 rank_list（查询）/checkout_rank（结算）；快照无则**重新 get_key** 再查，仍不存在则**不执行**并提示用户「榜单不存在」，并列出**当前已存在榜单**。 |
| **查询活动中存在的榜单** | 见下方「查询活动中存在的榜单」：从当前活动配置快照中解析并列出该活动**已配置的榜单**（如 rank_list、rank_type 或 special_info 下与排行榜相关的配置）；无快照时先 get_key 再解析并列出。**不调用** rank_list/checkout_rank，仅基于快照展示「当前活动已存在榜单：xxx」。用户表述示例：**查看当前活动存在哪些榜单**、列出活动中的榜单、当前活动有哪些排行榜等。 |
| **查询当前快照** | 见下方「查询当前快照」：**不调用 get_key**；直接展示**快照上下文**（act_id、region、默认 uid）及**快照内容摘要**（活动名称、礼物/奖池/兑换/榜单等可从快照解析的关键配置）；无快照时提示「当前无快照，请先提供 act_id 并拉取活动配置」。 |
| 红包雨送礼 | `skills/testing/data_testing/activity_test_skills/docs/其他接口文档.md`：`POST /voice_room/send_gift`；域名见该接口在文档中的「本接口域名」表，按区服对应 |
| **红包雨、触发下一阶段** | 见「红包雨测试方式」：**rid 须根据用户 ID 查询**（如 get_user_info 取用户房间列表）→ ① get_state（传 ActId、Uid、**rid**；**ActId、Uid、rid 均用数字类型**，rid 传房间 id **后六位的整型**，避免 412）得 trigger_gift_infos（小礼物 gift_id）与 next_value、current_val；② 配置中心 get_open_list 读 numbers；③ **本次送礼数量 = next_value**（**就送 next_value 件**，不做 next_value − current_val），按全局送礼最优方式调用 voice_room/send_gift（rid 同上），送完后再次 get_state 直至显示已进入下一阶段 |
| **查询抽奖/奖池信息** | **优先从活动配置快照** lottery[].type、cost_chip_meta_list 获取奖池 Type 与消耗；快照无时再使用活动接口 `lottery/get_lottery_info`、管理后台 `lottery/get_detail` 或配置中心 get_key。 |
| **抽奖执行流程** | ① **所需信息**：act_id、uid、区服、奖池 Type（**优先从快照 lottery[].type 获取**；无则 get_lottery_info 尝试常见 Type 或接口返回）、抽奖次数、消耗 chip_id/chip_num（**优先从快照 lottery[].cost_chip_meta_list 获取**；无则 get_key/接口返回）。② **查奖池**：`POST /activity_v2/lottery/get_lottery_info`，参数见活动信息接口文档。③ **碎片不足时**：按**全局碎片操作规则**——先查该 chip_id 是否存在（get_collect_chip 等），不存在则不添加并提示用户；存在则 `POST /activity_admin/add_collect_chip`（**单次 Number 最多 10000**，超过则分多次调用），参数见活动信息接口文档。④ **执行抽奖**：`POST /activity_v2/lottery/do_lottery`，参数见活动信息接口文档。返回 result 为奖励列表。 |
| **Bingo 礼物查询** | 管理后台 `POST /activity_admin/bingo/detail`：从 **result.gift_info** 取 bingo 礼物配置（gift_id、gift_type、numbers、region/distribute_region）；若 gift_info 缺字段再补查配置中心 `POST /assets/get_open_list`。 |
| **Bingo 玩法测试** | 见下方「Bingo 玩法（新增）」：先 `bingo/detail` 取 gift_info + 盘面，再查 rid，按 numbers 最优组合送 bingo 礼物（优先 voice_room/send_gift，失败 fallback send_gift_public），可再查 `bingo/detail` 验证 light_status/ret_coin/bonus。 |
| **Bingo All（循环点亮）** | 见下方「Bingo 玩法（新增）」：**不询问用户**，自动执行「查盘面 → 识别未点亮位置 → ret_coin 设置数字 → 送 1 件礼物 → 验证点亮」循环，失败位置记录后继续，最终返回成功/失败摘要。 |
| **活动兑换流程** | 见下方「活动兑换逻辑」：优先从快照查找兑换玩法与所需道具/数量 → **先查用户碎片是否满足**，**满足则直接兑换**，**不满足再**按全局碎片操作规则（先查碎片是否存在，单次最多 10000、超则分多次）add_collect_chip → `POST /activity_v2/exchange_store/exchange`；**参数见活动信息接口文档**。 |
| **榜单查询** | 见下方「榜单查询与结算（全局）」：**先查快照中是否存在当前要查询的榜单**，存在则 `POST /activity_admin/rank/rank_list`；不存在则**重新 get_key** 再查，仍不存在则**不查询**并提示用户「榜单不存在」，并列出**当前已存在榜单**。**参数见管理后台接口文档**。 |
| **榜单结算** | 见下方「榜单查询与结算（全局）」与「榜单结算（按当前逻辑整理）」：**单个榜单**先查快照存在则 `POST /activity_admin/rank/checkout_rank`（日榜传 datetime=当日/指定日期 YYYY-MM-DD，总榜不传）；**结算活动中所有榜单**则从快照解析全部榜单类型后依次 checkout_rank（日榜 period_type=1+datetime，总榜 period_type=0）。**参数见管理后台接口文档**。 |

**送礼前查询活动礼物 ID**（当用户要求送**小礼物、礼盒、盲盒、大礼物**等时，须先根据用户上下文中的 **act_id** 查询该活动下的对应 **gift_id**，再调用版本接口送礼；**参数见各接口文档**）：

**约定**：**优先从活动配置快照**（get_key 解析得到的 gift_list、special_info.small_gift_id/gift_box、extra_gifts、send_gift_hooker_v2 等）**获取**对应类型的 gift_id；**若快照中无或未建快照**，再按下表调用对应查询接口。

| 礼物类型 | 查询接口所在 | 方法·路径 | 说明 |
|----------|--------------|-----------|------|
| 礼盒 | 管理后台 | `POST /activity_admin/gift_box/get_act_gift_box` | 快照无时：返回该活动礼盒 gift_id 列表，参数见管理后台接口文档 |
| 盲盒 | 活动接口 / 管理后台 | 活动端 `POST /activity_v2/blind_box_lucky_value/get_info` 等 | 快照无时：从返回中取盲盒 gift_id，参数见活动信息接口文档 |
| 大礼物 | 活动接口 | `POST /activity_v2/extra_gift/get_choose_gift_info` | **大礼物指配置中心配置的大礼物**，并非以小搏大中的大礼物；快照无时从返回中取大礼物 gift_id，参数见活动信息接口文档 |
| 小礼物 / 普通礼物 | 管理后台 / 快照 | `GET /analysis_api/activity/get_prop_infos` 或**快照 special_info.small_gift_id / gift_list** | **查询小礼物**：优先从快照取 small_gift_id 或 gift_list 首项；快照无时调用 get_prop_infos，参数见管理后台接口文档 |

未在表中列出的礼物类型：在活动/管理后台接口文档中按「活动 + 礼物/道具/gift」关键词查找该活动下的礼物或配置查询接口，取得 gift_id 后再调用 `POST /game_api/send_gift_public`。

**送礼原则（全局）**：**只要涉及送礼**（包括但不限于版本接口 `send_gift_public`、红包雨 `voice_room/send_gift`、小礼物保底、礼盒、盲盒、触发下一阶段红包雨等），**均须**走同一套逻辑：① 先查礼物信息与配置中心 **numbers**（单次允许送的数量选项）；② 需送出多份时**按最优数量组合**——优先用允许的单次最大数量批量送，再以其余允许数量凑满目标，减少请求次数。**执行到送礼时，优先使用红包雨送礼接口**（`POST /voice_room/send_gift`）；若该接口无法执行（如该区服域名未配置、调用失败、返回错误等），再调用版本送礼接口（`POST /game_api/send_gift_public`）。不同场景仅**送礼接口与参数**不同（如版本接口 vs 红包雨接口），**查 numbers 与最优组合的规则全局一致**。

**送礼前必须查询礼物信息并校验**（在调用**任一**送礼接口之前执行；任一不通过则不调用送礼接口，直接中断并返回原因；**请求参数见配置中心接口文档**）：

1. **查询礼物信息**：配置中心 `POST /assets/get_open_list`，取得该礼物配置（含 gift_type、region/distribute_region、**numbers** 等）。
2. **校验 gift_type**：送礼请求中的 gift_type 必须与配置一致（如活动礼物=4、普通=0）；不一致则中断并返回「礼物类型与配置不符，gift_type 应为 x」。
3. **校验地区**：当前目标区服对应的 region 必须在配置的 region 或 distribute_region 中存在；不存在则中断并返回「该礼物在当前区服不可用」。
4. **校验数量**：确认用户拥有足够数量可送；不足则中断并返回「数量不足，无法送礼」。
5. **送礼数量配置与最优方式（全局）**：从配置读取 **numbers**（单次允许送的数量选项）。需送出多份时**按全局送礼原则**：优先用允许的单次最大数量批量送，再以其余允许数量凑满目标，减少请求次数。

仅当以上**五项**校验与配置读取均通过后，才调用送礼接口：**优先使用红包雨送礼接口** `POST /voice_room/send_gift`（需先根据用户 ID 查询 rid）；若该接口无法执行（如该区服域名未配置、调用失败、返回错误等），再调用版本送礼接口 `POST /game_api/send_gift_public`。**参数见版本接口文档、其他接口文档**。

**Bingo 送礼补充**：测试 Bingo 时，礼物配置优先取 `POST /activity_admin/bingo/detail` 返回的 **result.gift_info**（可直接拿 gift_id、gift_type、numbers、region/distribute_region）；仅当 gift_info 缺失关键字段时再补查配置中心 `POST /assets/get_open_list`。`POST /voice_room/send_gift` 返回键名为 **Code/Msg/Result**（大写），解析返回时按大写键名取值。

---

## Bingo 玩法（新增）

当用户要求「测试 bingo」「送 bingo 礼物」「bingo all」「循环点亮 bingo」时，按本节执行。

### Bingo 礼物定义与查询

- **Bingo 礼物定义**：bingo 礼物指 bingo 玩法中的礼物，独立于小礼物/礼盒/盲盒/大礼物。
- **查询接口**：管理后台 `POST /activity_admin/bingo/detail`（Body 传 ActId、Uid）。
- **提取字段**：
  - `result.gift_info`：gift_id、gift_type、numbers、region、distribute_region 等；
  - `result.bingo_info`：bingo、light_status、ret_coin、latest_ret_coins、bonus、round 等盘面状态。
- **补查规则**：若 gift_info 缺少 numbers/gift_type/region 等关键字段，再调用配置中心 `POST /assets/get_open_list` 补齐。

### 测试 Bingo（普通）

1. 调 `POST /activity_admin/bingo/detail` 获取 gift_info 与盘面状态。
2. 校验 gift_info：区服可用、送礼数量在 numbers 允许范围、gift_type 一致。
3. 调 `POST /censor/get_user_info` 获取真实 rid（result.rid 或 vip_room_list），**不可传 0/1**。
4. 按全局最优拆单送礼：
   - 优先 `POST /voice_room/send_gift`；
   - 失败时 fallback `POST /game_api/send_gift_public`。
5. 可选验证：再次 `bingo/detail` 检查 light_status/ret_coin/latest_ret_coins/bonus 是否更新。

### Bingo All（循环点亮）

**执行约束**：用户说「bingo all/循环点亮」时，**不询问用户**，自动执行完整循环。

1. `POST /activity_admin/bingo/detail` 获取当前盘面（bingo + light_status）。
2. 识别未点亮位置（0-24 中不在 light_status 的索引）。
3. 逐位置循环（可在循环开始前查一次 rid 并复用）：
   - `POST /activity_admin/bingo/ret_coin`：设置该位置对应数字；
   - 发送 1 件 bingo 礼物（优先 voice_room/send_gift，失败 fallback send_gift_public）；
   - 再次 `bingo/detail` 验证该位置是否点亮。
4. 若某位置点亮失败：记录失败并继续下一个位置，不中断全流程。
5. 结束条件：未点亮列表为空，或所有原始未点亮位置已尝试一次（避免无限循环）。
6. 返回结果：总尝试数、成功数、失败位置列表、是否全部点亮、round、bonus、关键日志摘要。

**业务规则（须先查再操）**

- **碎片**：**凡涉及添加或减少碎片**（含抽奖前补足、兑换前补足、用户主动要求添加/减少等），须**先查询该碎片是否存在**（如调用活动接口 `POST /activity_v2/collect_chip/get_collect_chip`，或从活动配置快照 collect_chip / 奖池 cost_chip_meta_list 等确认该 chip_id 在活动中已配置）。**若不存在则不执行添加或减少**，并**告知用户「没有当前碎片」**。**单次操作数量最大 10000**（添加或减少均适用）；若需添加/减少超过 10000，**分多次操作**（添加时多次调用 add_collect_chip，每次 Number 不超过 10000；减少时调用文档中对应的减少碎片接口，每次数量不超过 10000，具体接口与参数见活动信息接口文档、管理后台接口文档）。
- **碎片购买**：当用户要求**购买碎片**时，执行以下流程：① **从快照查找购买配置**：从当前活动配置快照的 **collect_chip** 数组中，找到对应 chip_id 的 **sell_conf.sell_infos**（购买档位配置）；若为空数组或不存在，则该碎片**不支持购买**，告知用户并停止。② **确认购买档位**：若用户未指定具体购买数量，则**向用户展示可用档位**（sell_infos 数组，含 number、price、extra_number、fe_id），由用户选择；用户指定数量时，**必须在 sell_infos 的 number 中存在**，不存在则提示用户并列出可用档位。③ **执行购买**：调用活动接口 **`POST /activity_v2/collect_chip/buy_collect_chip`**，Body 传 **ActId、Uid、ChipId、Number**（**大写键名，数值类型**），Number 为 sell_infos 中对应档位的 number 值。④ **展示结果**：购买成功后，告知用户**购买数量、花费钻石（price）、额外赠送（extra_number）、实际获得总数（number + extra_number）**。**参数见活动信息接口文档。**
- **抽奖**：先查奖池（`get_lottery_info`）与消耗（**优先从快照 lottery[].cost_chip_meta_list、lottery[].type 获取**；无则活动配置）；**碎片不足时有两条独立的业务线可选**：**业务线1-碎片购买**（正式业务，消耗钻石）：按下方「碎片购买」规则执行自动购买；**业务线2-碎片添加**（测试工具）：按「碎片」规则，先查该 chip_id 是否存在，不存在则提示用户、不添加；存在则 add_collect_chip（单次最多 10000，超则分多次）。**两条业务线相互独立**，用户可指定使用哪条业务线，或根据测试场景选择。碎片满足后调用 `POST /activity_v2/lottery/do_lottery`。**参数见活动信息接口文档、管理后台接口文档**。（涉及减少碎片时同样按「碎片」规则：先查存在，单次最多 10000，超则分多次。）
- **任务**：完成/领取前须查询该任务是否存在，不存在则不调用并提示「该任务不存在」。**清除任务状态**：`POST /activity_admin/task/clear_data`。**测试任务完成步骤**（先查所有任务状态 → 区分每日/阶段任务 → 按需调整数值 → 再领取）：① 查询任务状态 `POST /activity_v2/task_group/get_group_list`，从返回解析 stages、condition_value、next_stage_id、repeat_times。② 调整数值 `POST /activity_admin/task/incr_condition_value`，ConditionId 取 condition_map 的 key，Value 为达到下一阶段目标需增加的量。③ 再次 get_group_list 后，对 state=1 且 receive_times=0 的阶段用 `POST /activity_v2/task_group/receive_task_reward` **按任务逐阶段领取**；多阶段任务若在第一阶段领取即报错则该任务后续阶段不再请求。**以上接口参数均见活动信息接口文档、管理后台接口文档**。
- **金币不足**：涉及消耗金币且当前金币不足时，提醒用户手动添加金币，不代为扣减或充值。
- **送礼**：**礼物 gift_id 优先从活动配置快照获取**（special_info.small_gift_id、gift_box、gift_list、extra_gifts 等），无则按「送礼前查询活动礼物 ID」调接口；再按「送礼前必须查询礼物信息并校验」执行（**含全局送礼最优方式**：读 numbers，多份时按最优数量组合）；通过后**优先调红包雨送礼接口**（`POST /voice_room/send_gift`，需先根据用户 ID 查 rid），若该接口无法执行再调版本送礼接口（`POST /game_api/send_gift_public`）；**语音房/红包雨场景下 rid 须根据用户 ID 查询**（如 get_user_info 取 vip_room_list），再用于 get_state 与 voice_room/send_gift；未提供 rid 时先查 get_user_info 取 vip_room_list，无则 rid 传 1 或 0；若返回「礼物卡数量不足」则将 IsGiftCard 改为 0 再请求。**参数见版本接口文档、配置中心接口文档、其他接口文档**。

**活动兑换逻辑**（当用户要求进行**活动兑换**时，按以下顺序执行；**接口路径与参数以 `skills/testing/data_testing/activity_test_skills/docs/活动信息接口文档.md`、管理后台接口文档、配置中心接口文档为准**）：

1. **从快照查找兑换玩法**
   - **优先从当前活动配置快照中查找**是否存在兑换相关配置（如 exchange_store、exchange_list、store_list、或 special_info 下兑换商店相关字段）。若存在，从配置中解析：**兑换 type**（即接口中的 exchange_type，可能为配置项 id 或类型标识）、**store_name**（兑换商店名称）、以及**兑换所需道具及数量**（如消耗碎片则含 chip_id、chip_num；若为其他道具则以实际配置字段为准，如 cost_list、cost_chip_meta 等）。
   - **若用户已给出要兑换的东西**（兑换项 ID 或名称）**及数量**：则用该信息确定 exchange_type 与 exchange_count，进入步骤 2。
   - **若用户未给出**要兑换的东西或数量：**先向用户询问**「需要兑换的东西（ID 或名称）以及数量」，待用户补充后再继续；若用户不补充则停止后续步骤。
   - **若快照中未找到兑换配置**：**重新调用配置中心** `POST /config/get_key`（region、namespace=activity、key=act_id、app_id=1）拉取活动配置，解析 result.value 后再次在快照中查找兑换玩法。
   - **若重新 get_key 后仍无兑换配置**：**停止后续步骤**，并**提示用户**「当前活动配置中未找到兑换玩法，无法执行兑换」。

2. **兑换前校验用户碎片（或所需道具）**
   - **先查询**当前用户在该活动下是否**已拥有**兑换所需数量的碎片（或所需道具）：调用活动接口 **`POST /activity_v2/collect_chip/get_collect_chip`**（参数见活动信息接口文档）查询用户碎片数量；或通过 **`POST /activity_v2/exchange_store/get_exchange_info`**（传 act_id、uid、store_name、exchange_type）从返回中获取所需道具与数量及用户当前持有量。
   - **若用户碎片（或所需道具）已满足**兑换所需数量：**不需要添加碎片**，直接进入步骤 3 执行兑换。
   - **若不满足**：再按**全局碎片操作规则**：先查询该 chip_id 是否存在，不存在则提示用户、不执行添加；存在则调用管理后台 **`POST /activity_admin/add_collect_chip`**（单次 Number 最多 10000，超过则分多次），按兑换所需 **chip_id** 与**不足的**数量补足；补足后再执行步骤 3。

3. **执行兑换**
   - 调用活动接口 **`POST /activity_v2/exchange_store/exchange`**，Body 传 **act_id、uid、target_uid**（一般为当前用户 uid）、**store_name、exchange_type、exchange_count**（兑换数量）；若接口文档要求大写键名则使用 ActId、Uid、TargetUid 等。**参数以活动信息接口文档为准。**

4. **兑换成功后展示**
   - 兑换接口返回成功（如 code 200）后，**展示兑换结果**：兑换的**物品/奖励名称或 ID** 以及**数量**（可从接口 result 或上述 get_exchange_info 的配置中对应得到）；若返回中无明确文案，可摘要为「兑换成功，兑换项：xxx，数量：N」。

**榜单查询与结算（全局）**（当用户要求**查询榜单**或**结算榜单**时，均按以下顺序执行；**接口路径与参数以 `skills/testing/data_testing/activity_test_skills/docs/管理后台接口文档.md` 为准**）：

1. **执行前先查快照中是否存在当前榜单**
   - **若当前无活动快照**（未提供 act_id 或快照未初始化）：**按快照上下文入参**（见「未指定 act_id、uid 时的入参约定（全局）」）；若无快照则先向用户确认活动 ID 或使用当前会话中的活动 ID，再执行 get_key 初始化快照（若尚未有该 act_id 快照），然后继续下述步骤。
   - **优先从当前活动配置快照中查找**是否存在用户要**查询或结算**的**当前榜单**（根据用户指定的 **rank_type**、**period_type** 等与快照中的榜单配置匹配；快照中可能含 rank_list、rank_type 或 special_info 下与排行榜相关的配置，以实际 value 结构为准）。
   - **若存在**：
     - **查询榜单**：调用管理后台 **`POST /activity_admin/rank/rank_list`**（Body 传 uid、act_id、rank_type、period_type、limit、offset、lang 等，参数见管理后台接口文档）。
     - **结算榜单**：调用管理后台 **`POST /activity_admin/rank/checkout_rank`**（Body 传 uid、act_id、rank_type、period_type、lang 等，**参数见管理后台接口文档**）。**日榜结算时的日期**：若结算的是**日榜**（period_type=1 或 rank_type 为活动配置中的日榜类型，如 daily_rank），**未指定日期**时默认使用**当日日期**，**指定了日期**则**优先使用指定日期**；日期格式为 **YYYY-MM-DD**（如 2026-02-27），通过接口文档中的 **datetime** 参数传入。**总榜**（period_type=0）结算时不传 datetime。
   - **若快照中未找到该榜单**：**重新调用配置中心** `POST /config/get_key`（region、namespace=activity、key=act_id、app_id=1）拉取活动配置，解析 result.value 后**再次在快照中查找**该榜单是否存在。
   - **若重新 get_key 后仍不存在**：**不执行查询或结算**，并**提示用户**「榜单不存在」；同时**列出当前快照中已存在的榜单**（如已配置的 rank_type 列表或榜单标识），告知用户「当前已存在榜单是：xxx」。

**榜单结算（按当前逻辑整理）**：

- **结算单个榜单**（用户指定了要结算的榜单类型，如「结算总榜」「结算日榜」）：按上述「执行前先查快照中是否存在当前榜单」→ 存在则调用 **checkout_rank**，传 uid、act_id、rank_type、period_type、lang；**日榜**时传 **datetime**（未指定日期=当日 YYYY-MM-DD，指定了=指定日期）；**总榜**不传 datetime。参数以管理后台接口文档为准。
- **结算活动中所有榜单**（用户要求「结算所有榜单」「结算活动中所有榜单」等）：① 从**当前活动配置快照**解析该活动**已配置的所有榜单类型**（如 special_info.daily_rank_type / rank_type → 日榜，special_info.total_rank_type → 总榜；以实际快照结构为准）。② 对每个榜单类型**依次**调用 **`POST /activity_admin/rank/checkout_rank`**：
  - **日榜**：rank_type=快照中的日榜类型（如 daily_rank），period_type=**1**，**datetime=当日日期**（未指定日期时取当日，格式 **YYYY-MM-DD**）；用户指定了日期则用指定日期。
  - **总榜**：rank_type=快照中的总榜类型（如 total_rank），period_type=**0**，**不传** datetime。
  - 其他榜单类型按快照与接口文档对应（若有 period_type 与日期约定则同上）。
③ uid、act_id、lang 未指定时按快照上下文入参。**参数与日期格式以 `skills/testing/data_testing/activity_test_skills/docs/管理后台接口文档.md` 为准**（含 datetime）。

**查询活动中存在的榜单**（当用户仅要求**查询活动中存在哪些榜单**、**列出活动中的榜单**等，不指定具体 rank_type/period_type 做查询或结算时）：

- **从当前活动配置快照中解析并列出**该活动**已配置的榜单**：快照中可能含 **rank_list**、**rank_type** 或 **special_info** 下与排行榜相关的字段；从中解析出当前活动已存在的榜单类型/标识（如 rank_type 取值列表、榜单名称或 ID 等，以实际 value 结构为准），整理后展示给用户，例如「当前活动已存在榜单：xxx」。
- **若当前无活动快照**（未提供 act_id 或快照未初始化）：**按快照上下文入参**（见「未指定 act_id、uid 时的入参约定（全局）」）；若无快照则先向用户确认活动 ID 或使用当前会话中的活动 ID，再调用配置中心 **`POST /config/get_key`**（region、namespace=activity、key=act_id、app_id=1）拉取活动配置，解析 result.value 后从快照中按上段规则解析并列出已存在榜单。
- **不调用** rank_list、checkout_rank；仅基于快照内容展示「活动中存在的榜单」列表。

**查询当前快照**（当用户要求**查询当前快照**、**查看当前快照**、**当前快照有哪些配置**等时）：

- **不调用 get_key**；直接基于**当前已存在的活动配置快照**进行展示。
- **若有快照**：展示 **快照上下文**（当前快照对应的 **act_id**、生成快照时使用的 **region**、快照上下文中记录的**默认 uid**（若存在）），以及 **快照内容摘要**（从快照解析出的关键配置，如活动名称 activity_name、gift_list、special_info 下小礼物/礼盒、lottery 奖池类型、兑换 store 列表、榜单 rank/rank_type 等，以实际 value 结构为准，可结构化列出）。
- **若无快照**（尚未执行过 get_key 或快照已清空）：提示用户「当前无快照，请先提供 act_id 并拉取活动配置」（或先输入 act_id 以触发 get_key 初始化快照后再查询）。

---

## 操作约定（AI 执行时）

**执行前**
- **执行测试流程时**：须**一步一步执行**——按流程顺序逐步调用接口、确认上一步结果或返回后再进行下一步；不得跳过或合并步骤，不得一次性批量执行多步后再统一反馈。
- **每次用户输入 act_id 时**：先在快照中查是否**已存在该 act_id** 的配置；**若已存在则不调用 get_key**（不需要初始化）；**若不存在**则调用配置中心 **get_key**（region、namespace=activity、key=act_id、app_id=1）获取活动完整配置，解析 result.value 建立**活动配置快照**，**并删除之前的快照、仅保留当前 act_id 的快照**；同时**记录快照上下文**（该 act_id、本次 get_key 所用 region、以及若用户已提供则记录 uid）。后续测试操作**优先从快照获取**礼物 id、奖池 Type、消耗等，**获取不到时再通过 get_prop_infos、get_act_gift_box、get_lottery_info 等接口获取**。**未指定 act_id、uid 时**：**按生成快照时的数据入参**（见「未指定 act_id、uid 时的入参约定（全局）」），使用快照上下文中的 act_id、uid、region 作为接口入参。
- 用户需要查询/检查时，可**优先从快照**取数；快照不足时再调用 `POST /activity_admin/check/activity_config_check` 等。
- **测试小礼物/礼盒/盲盒/大礼物时**：按「测试规则（小礼物/礼盒/盲盒/大礼物）」**先从快照取对应类型礼物 ID**（small_gift_id、gift_box、gift_list、extra_gifts 等），无则再查对应接口；再根据用户想测试的内容自动触发后续流程。**测试小礼物保底**时须执行完整流程：查 get_guarantee，**若返回 result[以小搏大触发的大礼物id] 为数字则表示已送件数**，need_times = 保底总数(从快照 extra_gifts[].random_list[].guarantee 取) − 该数；若为对象则直接取 need_times → **小礼物 gift_id 优先从快照**（见「快照中四类礼物的区分」）取，无则 get_prop_infos → 配置中心校验并读 numbers → 按最优数量组合送满 need_times → **再次 get_guarantee** → **确认保底触发**：**送礼流程走完后 need_times=0 时才算已经触发保底**；若接口返回 **cur_times=0 且 need_times=保底总数**（触发后直接进入新一轮），同样视为已触发保底。**trigger_map 增加只表示爆出以小搏大中的大礼物**（可能随机可能保底），不能单独作为保底依据。若 need_times 未为 0 且非上述新一轮情形则按 need_times 继续送并重复直至**送满后 need_times=0 或 cur_times=0 且 need_times=保底总数**。**测试礼盒保底**时：**礼盒 gift_id 优先从快照 special_info.gift_box 或 gift_list 取**，无则 get_act_gift_box → get_gift_box_guarantee（活动接口域名）得 N → set_guarantee val=N-1 → 校验并读 numbers → 送 1 份礼盒触发保底。**红包雨测试（触发下一阶段）**时：**先根据用户 ID 查询语音房 rid**（如 get_user_info 取 vip_room_list）→ get_state（ActId、Uid、rid **均用数字类型**；rid 传房间 id **后六位的整型**，避免 412）得 trigger_gift_infos（小礼物 gift_id）、next_value、current_val；**本次送礼数量 = next_value**（**就送 next_value 件**，不做 next_value−current_val 的减法）→ 配置中心 get_open_list 读 numbers → **按全局送礼最优方式**调用 **voice_room/send_gift**（rid 同上）送满 **next_value** 件，再次 get_state 直至显示已进入下一阶段。**参数见各接口文档。**

**查找与参数**
- **必须**从接口文档（活动/管理后台/版本/配置中心/其他接口）查找接口，不得编造路径或参数；**所有参数（含键名大小写、类型、成功示例）以各接口文档为准**，本 Skill 不在此罗列参数调整。
- **域名严格按照文档要求**：**活动/管理后台/版本**接口的域名**必须**从本 Skill「测试环境各服域名」表（按目标区服）查表取用；**其他接口**的域名**必须**从 `skills/testing/data_testing/activity_test_skills/docs/其他接口文档.md` 该接口的「本接口域名」表取用；**配置中心**使用该文档 Base URL。**禁止**按区服名称自行推断或拼写域名（如不得因「法语服」而自造 fr 等子域）。
- **域名**：管理后台用管理后台各服域名，版本接口用版本接口各服域名；配置中心、其他接口使用对应接口文档中的 Base URL/域名。
- **区服域名为空**：取域名时，若**该接口**在对应文档中目标区服的域名为空或未配置（如其他接口文档中该接口的「本接口域名」表该服为「待补充」），则**不调用该接口**，**中断流程**并返回原因（如：「区服 [服名] 的 [接口路径] 域名未配置，无法调用」）。
- **无需求不重复调用**：**没有明确需求时，不允许重复调用**同一接口或为同一目的的多余调用；已有结果可复用时直接复用（**快照按 act_id 唯一保留，当前 act_id 已在快照中则复用、不重复 get_key**；礼物 id、奖池 Type 等优先从快照取），不得无谓多次请求。
- **建议**按前置 → 主流程 → 校验顺序组织请求；用户或用例已指定顺序时以指定为准。
- **测试**（所有测试流程，如测试小礼物保底、测试礼盒保底等）：均按流程**直接调用各接口**完成，**非必要不编写脚本**——即**不生成、不新增**测试脚本文件；仅当用户**明确要求**「生成脚本」「写个 Python 跑」「保存成脚本」等时再生成或修改脚本。执行测试时以**依次请求各接口、传递上一步结果到下一步、汇总返回**的方式完成，不依赖新建脚本文件。
- 无匹配接口时：提示「接口文档中未找到与步骤 xxx 匹配的接口」，并给出相近模块或接口名。

**问题容错处理机制**（执行失败或结果不符合预期时，按问题类型采用对应方案，**不得省略重要步骤**）：

| 问题类型 | 判定方式 | 处理方案 | 约束 |
|----------|----------|----------|------|
| **脚本问题** | 执行报错（语法、运行时异常）、或脚本逻辑与本 Skill 规则不一致（如最优数量用了最小值、缺少「再次 get_guarantee 并循环」等） | **方案一：检测并修改脚本**。根据报错信息或与本 Skill 中该流程的「重要步骤」「执行检查与常见错误」对照，定位并修正脚本（语法、参数、逻辑、缺步）；修改后**重新执行**，直至通过或确认为非脚本问题。 | **不得省略重要步骤**：修改脚本时必须以本 Skill 中该流程的**重要步骤**为检查清单（如测试小礼物保底中的 get_guarantee 用 form、小礼物从快照取、numbers 按单次最大组合、先查 rid、送满后循环再 get_guarantee 直至触发等），**严格按照重要步骤执行**，不得为“能跑通”而跳过或合并关键步骤。 |
| **描述问题或理解不清** | 用户表述模糊、缺少关键信息（如未指定 act_id/uid 且快照无、未指定兑换项/数量、未指定榜单类型等）、或执行结果与用户预期不符且无法判断是脚本问题还是需求理解错误 | **方案二：再次询问用户**。明确向用户说明当前理解或执行结果，指出**需要澄清的点**（如「请确认要结算的是日榜、总榜还是全部榜单」「请提供活动 ID 或确认使用当前快照 act_id」），待用户补充或确认后再继续执行。 | 在未得到用户澄清前，**不擅自猜测**并执行可能改变业务状态的操作；仅做查询类操作或明确安全的步骤时，可说明「当前按 xxx 理解执行，若不符请补充」。 |

**执行时的使用方式**：先区分问题类型 → 属脚本问题则采用方案一（检测脚本、修改脚本、严格按重要步骤执行）；属描述或理解不清则采用方案二（再次询问用户）。若修改脚本后仍失败，且无法判断是脚本遗漏还是需求不明，应**同时**说明已做的修正与仍存在的现象，并**向用户询问**是否还有约定条件或期望结果，再决定继续改脚本还是按用户补充执行。

- **碎片 / 抽奖 / 任务 / 金币不足**：与上文「业务规则（须先查再操）」一致；**添加或减少碎片前须先查该碎片是否存在**，不存在则不执行并告知用户「没有当前碎片」；**单次添加/减少数量最多 10000**，超过则分多次操作。抽奖前查奖池与资源，任务前查存在，金币不足时提醒用户添加。
- **送礼**：按「送礼前查询活动礼物 ID」→「送礼前必须查询礼物信息并校验」执行（**多份时按全局送礼最优方式**）；校验不通过则中断返回原因，通过后**优先调红包雨送礼接口**（`POST /voice_room/send_gift`），若无法执行再调版本送礼接口（`POST /game_api/send_gift_public`）；rid、IsGiftCard 处理同上文。
- **Bingo**：测试 bingo 时优先 `POST /activity_admin/bingo/detail` 获取 gift_info 与盘面；送礼前仍需做数量/地区/gift_type 校验，rid 必须由 `get_user_info` 获取；`bingo all` 场景按本 Skill 的自动循环规则执行（不询问用户、失败位置记录后继续）。
- **兑换**：按「活动兑换逻辑」执行：**优先从快照查找兑换玩法**（exchange_type、store_name、所需 chip_id/chip_num）；用户未给兑换项或数量时**先询问**；快照无则**重新 get_key**，仍无则**停止并提示用户**；兑换前**先查用户碎片是否满足**兑换所需，**满足则直接兑换**，**不满足再**按全局碎片操作规则添加碎片后调用 **exchange_store/exchange**；成功后**展示兑换的东西及数量**。**参数见活动信息接口文档、管理后台接口文档。**
- **榜单查询**：按「榜单查询与结算（全局）」执行：**先查快照中是否存在当前要查询的榜单**（rank_type、period_type 等与快照匹配），存在则调用 **activity_admin/rank/rank_list**；快照无则**重新 get_key** 再查，**仍不存在则不查询**并提示用户「榜单不存在」，并列出**当前已存在榜单是哪些**。**参数见管理后台接口文档。**
- **榜单结算**：按「榜单查询与结算（全局）」及「榜单结算（按当前逻辑整理）」执行：**结算单个榜单**时先查快照存在则 **activity_admin/rank/checkout_rank**（日榜传 **datetime**=当日/指定日期 YYYY-MM-DD，总榜不传）；**结算活动中所有榜单**时从快照解析全部榜单类型（日榜、总榜等），依次 checkout_rank（日榜 period_type=1、datetime=当日或指定日期，总榜 period_type=0、不传 datetime）。快照无则**重新 get_key** 再查，**仍不存在则不结算**并提示「榜单不存在」，并列出**当前已存在榜单**。**参数见管理后台接口文档。**
- **查询活动中存在的榜单**：按「查询活动中存在的榜单」执行：从**当前活动配置快照**中解析 rank_list、rank_type 或 special_info 下与排行榜相关的配置，**列出该活动已存在的榜单**并展示；无快照时先 get_key 再解析并列出。**不调用** rank_list/checkout_rank。
- **查询当前快照**：按「查询当前快照」执行：**不调用 get_key**；直接展示**快照上下文**（act_id、region、默认 uid）及**快照内容摘要**（活动名称、礼物/奖池/兑换/榜单等）；无快照时提示「当前无快照，请先提供 act_id 并拉取活动配置」。

**调用后统计**
- **每次调用接口且返回成功**（如 code 200）后，须将**调用成功的接口**（方法 + 路径）及**本次使用的主要参数/成功参数**（可摘要）按**接口文档分类**填写到 **`skills/testing/data_testing/activity_test_skills/README.md`** 的「接口使用情况统计」对应分类下；**仅填写接口与使用方法**（方法、路径、成功参数、简短用法说明），**不写流程或业务逻辑**。
- **已在该统计中填写过的接口**（以 **方法 + 路径** 为准）**不重复填写**，仅补充尚未出现的接口记录，便于后续接口使用情况统计。
- 分类与接口文档对应关系：活动信息接口文档、管理后台接口文档、版本接口文档、配置中心接口文档、其他接口文档（见 `skills/testing/data_testing/activity_test_skills/README.md` 中各小节标题）。

---

## 简要流程小结

```
活动信息：**每次用户输入 act_id** → 先查快照是否已有该 act_id；**已有则不调用 get_key**；**没有则 get_key 初始化，并删除之前快照、仅保留当前 act_id 快照**；**记录快照上下文**（act_id、region、若已提供则 uid）；后续操作优先从快照获取礼物 id、奖池 Type、消耗等，获取不到再通过 get_prop_infos、get_act_gift_box、get_lottery_info 等接口；**未指定 act_id、uid 时按快照上下文入参**。
步骤执行：步骤意图 → 在对应接口文档中查找接口 → 取域名、拼 URL、构造请求。**测试流程**均**直接调各接口**完成，**非必要不编写脚本**；执行时须**一步一步执行**（逐步调用、确认上一步后再进行下一步，不跳过、不合并、不批量执行多步后统一反馈）；仅当用户明确要求生成/运行脚本时再生成。
测试小礼物/礼盒/盲盒/大礼物：**礼物 ID 优先从快照取**，无则再按类型调接口查 → 再按用户测试意图自动触发流程；测试小礼物保底：get_guarantee（**返回若为 result[key]=数字 则表示已送件数，need_times=保底总数−该数**，保底总数从快照 extra_gifts 取）→ 小礼物 id 从快照取（见四类区分）→ 校验并读 numbers → 按最优组合送满 need_times → 再次 get_guarantee → **确认保底触发**：**need_times=0** 即已触发，或 **cur_times=0 且 need_times=保底总数**（触发后进入新一轮）同样视为已触发；**trigger_map 增加只表示爆出以小搏大中的大礼物**，可能随机可能保底，不能单独作为保底依据。未触发则按 need_times 继续送直至 need_times=0 或 cur_times=0 且 need_times=保底总数。测试礼盒保底：礼盒 id 从快照 gift_box/gift_list 取（无则 get_act_gift_box）→ get_gift_box_guarantee → set_guarantee val=N-1 → 送 1 份礼盒触发保底。**参数见各接口文档。**
送礼（小礼物/礼盒/盲盒/大礼物/红包雨等）：**所有涉及送礼的场景均按全局送礼原则**：gift_id 优先从快照获取，无则按「送礼前查询活动礼物 ID」调接口 → 再查配置中心礼物信息并校验 gift_type、地区、数量，**并读取 numbers**；需送多份时**按最优数量组合**（优先单次最大允许数量再凑满）→ **优先调红包雨送礼接口**（voice_room/send_gift，需先根据用户 ID 查 rid），若该接口无法执行再调版本送礼接口（send_gift_public）。
红包雨测试（触发下一阶段）：**rid 须根据用户 ID 查询**（如 get_user_info 取用户房间列表）→ get_state（传 ActId、Uid、rid）→ trigger_gift_infos 取小礼物 gift_id，next_value、current_val；**本次送礼数量 = next_value**（**就送 next_value 件**，不做减法）→ get_open_list 读 numbers → 按全局送礼最优方式调用 voice_room/send_gift（rid 同上）送满 **next_value** 件，再次 get_state 直至已进入下一阶段；域名见其他接口文档「本接口域名」。
抽奖：奖池 Type、消耗 chip_id/chip_num **优先从快照 lottery 取**，无则 get_lottery_info/get_key；get_lottery_info → 碎片不足时**先查该碎片是否存在**，不存在则提示用户、不添加；存在则 add_collect_chip（**单次最多 10000，超则分多次**）→ do_lottery。**参数见活动信息接口文档。**
Bingo：普通 bingo 测试流程为 bingo/detail 取 gift_info 与盘面 → 查 rid → 按 numbers 最优组合送礼（优先 voice_room/send_gift，失败 fallback send_gift_public）→ 再查 bingo/detail 验证。`bingo all` 为自动循环点亮：识别未点亮位置 → ret_coin 设置该位数字 → 送 1 件礼物 → 验证点亮；失败位置记录后继续，最终返回汇总。
兑换：**优先从快照查找兑换玩法**（exchange_type、store_name、所需 chip_id/chip_num）；用户未给兑换项或数量则**询问**；快照无则**重新 get_key**，仍无则**停止并提示**；兑换前**先查用户碎片是否满足**，**满足则直接兑换**，**不满足再**按碎片操作规则添加碎片后 **exchange_store/exchange**；成功后**展示兑换的东西及数量**。**参数见活动信息接口文档。**
榜单查询：**先查快照中是否存在当前要查询的榜单**（rank_type、period_type 等与快照匹配），存在则 **activity_admin/rank/rank_list**；快照无则**重新 get_key** 再查，**仍不存在则不查询**并提示用户「榜单不存在」，并列出**当前已存在榜单是哪些**。**参数见管理后台接口文档。**
榜单结算：按「榜单结算（按当前逻辑整理）」：**单个榜单**先查快照存在则 **activity_admin/rank/checkout_rank**（日榜传 **datetime**=当日/指定 YYYY-MM-DD，总榜不传）；**结算活动中所有榜单**则从快照解析全部榜单类型后依次 checkout_rank（日榜 period_type=1+datetime，总榜 period_type=0）。快照无则**重新 get_key** 再查，**仍不存在则不结算**并提示「榜单不存在」，并列出**当前已存在榜单**。**参数见管理后台接口文档。**
查询活动中存在的榜单：从**当前活动配置快照**解析 rank_list、rank_type 或 special_info 下榜单相关配置，**列出该活动已存在的榜单**并展示；无快照时先 get_key 再解析列出；**不调用** rank_list/checkout_rank。
查询当前快照：**不调用 get_key**；直接展示**快照上下文**（act_id、region、默认 uid）及**快照内容摘要**（活动名称、礼物/奖池/兑换/榜单等）；无快照则提示「当前无快照，请先提供 act_id 并拉取活动配置」。
顺序：前置（**按 act_id 查快照，无则 get_key 并仅保留当前快照**；**记录快照上下文** act_id、region、uid）→ 主流程 → 校验；**未指定 act_id、uid 时按快照上下文入参**；**所有接口参数以对应接口文档为准**。
**碎片添加/减少（全局）**：**先查询该碎片是否存在**（**`POST /activity_v2/collect_chip/get_collect_chip`** 或快照 collect_chip）；**不存在则不执行添加或减少**，告知用户「没有当前碎片」；**单次操作数量最多 10000**（添加或减少均适用），超过则分多次操作（添加时多次 add_collect_chip；减少时调用文档中对应的减少碎片接口，每次不超过 10000）。
**碎片购买（全局）**：从快照 **collect_chip[].sell_conf.sell_infos** 查购买档位，为空则不支持购买；用户未指定数量时**展示可用档位**；指定数量须在 sell_infos 的 number 中存在；调用 **`POST /activity_v2/collect_chip/buy_collect_chip`**（Body 传 **ActId、Uid、ChipId、Number**，**大写、数值**）；成功后展示**购买数、花费、赠送、实际获得**。**参数见活动信息接口文档。**
**问题容错**：执行失败或结果不符预期时，**脚本问题**→ 检测并修改脚本，**不得省略重要步骤**、须严格按本 Skill 重要步骤执行；**描述或理解不清**→ **再次询问用户**澄清后再执行。
```
