# 线上现况 vs 既有档案 · 冲突与缺口清单

> **这份档是知识库存在的理由。** Axure 是设计稿、PRD 是意图，**线上后台才是现况**。
> 三者对不上的地方，都记在这里。
> 编号 `C-NNN` 永不复用。v0.25 · 2026-09-05（🆕 **新增 `C-032`，当日开、当日结**（`ruling:R-197`）：`case:27` 的**线上「协议没勾就按主按钮」会出一句 Toast，而 PRD `§2.5.2` ／ `§2.5.4` ／ `AC17` 三处都写「一句都不出」**。<br>🔴 **不是开发做错** —— Luke 逐字「**既然现在发现，并且已经实现了，那就改 PRD+原型图**」⇒ 改档，不改行为。<br>🔴 **`R-193` 同批收窄**：它的落点把「协议」写进静默名单，而**逐字裁定只讲了手机号与 OTP**。<br>⚠️ **与 `C-028` 同一族的第二例，更深一层**：`C-028` 打架的是文案逐字，本条打架的是**行为**。<br>**32 条：30 已结 ／ 2 挂账 ／ 0 待查 ／ 0 未结**）。v0.24 · 2026-09-05（🆕 **档头「读法」加一节「什么**不**进这份档」**：发布落後不算冲突，那是待办（`ruling:R-196`）｜ v0.23 · 2026-09-04（🆕 **新增 `C-031`，当日开、当日结**（Luke 逐字「**C**」）：`case:27` 的**需求原文 5.5 说「按钮置灰禁用」，PRD §2.5.3 说「不做成 `disabled`、仍点得下去」**。<br>🔴 **不是 PRD 写错** —— 是 Luke 2026-08-28 在 `v1.2` 亲自改的；真正的洞是**需求原文没跟着改，PRD 也没指回去说推翻了哪一条**。<br>🔴 **炸点**：开发照需求原文做成 `disabled` ⇒ `disabled` 不派发点击事件 ⇒ `AC16` 那句 Toast 永远出不来，**而画面看起来完全正常**。<br>⚠️ **`lint_prd` 看不见这一类** —— 它只查一份档自己，不比对同资料夹里另一份档。<br>**触发源**：第一次走 OpenRouter 的 Codex 外审，35 条判定 34 条过，唯一 `CONTRADICTED` 就是它。<br>**31 条：29 已结 ／ 2 挂账 ／ 0 待查 ／ 0 未结**）。v0.22 · 2026-09-03（✅ `C-029` ／ `C-030` 同日开、同日结：改闸不改流程 ＋ 两份标准补归属判准）v0.19 · 2026-09-02（✅ **`C-027` 与 `C-028` 同日结清，剩下的两条都是挂账、没有待查**。<br>**`C-027`**：Luke 答「**两支都叫**」⇒ `Rekognize` 串了 `IndexFaces` ＋ `SearchFacesByImage`，`case:04` `§6.3` 入库状态机漏了一个触发源，**`OP-25` 的前提不成立、当场结案**。<br>**`C-028`**：Luke 给了线上截图并裁「**照截图**」⇒ 那句**真的在线上跑**，文案库原写「拟稿、未实现」是错的；**但逐字与 PRD 差三处**（逗号后无空格 ／ `resent` 不是 `resend` ／ 结尾有句点），线上是 `Incorrect verification code,please resent.`。🔴 **两句各管各的流程**：注册／登录用它，绑定电子钱包用 `Verification code invalid`。<br>**28 条：26 已结 ／ 2 挂账 ／ 0 待查 ／ 0 未结**）。v0.18 · 2026-09-01（🆕 **新增 `C-028`** 🟡 待查：`case:27` 的「验证码错误」文案，PRD `§3.4` B 段说「**沿用既有、这四条线上已经有了**」，而 [`../PRD_Spec/91_common_toasts.md`](../PRD_Spec/91_common_toasts.md) 第 66 行逐字说那句是「**拟稿、未实现**」（依据 Luke 2026-08-31 实测）。<br>🔴 **炸点是 icon 标错**——`✅`（线上既有，照抄）与 `📐`（本 PRD 拟稿，上线前要核）给开发的指令不同。<br>**处置**：`27C` 提示语表照 PRD 列，但 icon 标 `📐`，出处行指向本条。**28 条：24 已结 ／ 2 挂账 ／ 2 待查 ／ 0 未结**）。v0.17 · 2026-09-01（🆕 **新增 `C-027`** 🟡 待查：`Rekognize` 按钮到底做几件事。Luke 记得它「**同时把脸上传并且查找**」，而 `PRD_v1.4_KYCFaceSimilarity` `§4` 逐字写的是「**重发查重**」、`§6.3` 入库状态机里入库只有「KYC 提交」一个触发源。<br>🔴 **查了 AWS 官方文档：那是两支不同的 API**——`IndexFaces` 只存不搜、`SearchFacesByImage` 只搜不存，**没有一支同时做**；要两件都做得由后端自己串两支。<br>⚠️ **本条刻意不下判断**：官方文档只证明「AWS 没有一支 API 同时做」，**不证明「后端没有串两支」**，而本库查不到平台代码。<br>🔴 **炸点是 `OP-25`**：`§6.4` 写「待人工补入库目前没有入口」——若 `Rekognize` 也叫了 `IndexFaces`，那入口早就有、`OP-25` 白问；若没有，则这笔 KYC 审过了库里却没脸，下一个人拿同一张脸来注册查不出来。<br>**27 条：24 已结 ／ 2 挂账 ／ 1 待查 ／ 0 待裁**）。v0.16 · 2026-09-01（🆕 **新增 `C-023`~`C-026` 四条，全数已结**，触发源需求 `31.自我限制BetLimit新增周与月` 收尾回写（工作记录在 `待评审/31.…/连动清单.md` §九，原候选号 `C-b`／`C-c`／`C-e`／`C-g`；`C-a` 我方笔误不发号、`C-d`／`C-f` 误报撤销）。🔴 其中 **`C-024` 是真的线上冲突**：`Daily Game Duration` 上线时要改名。**26 条：24 已结 ／ 2 挂账 ／ 0 未结**）。v0.15 · 2026-08-28（🆕 **新增 `C-022`** ⬜ 未结，触发源需求 `30`：`Frozen/UnFroze Log` 的 `冻结状态` 中文 **5 个值**，与 `Freeze_冻结` 页的 `Freeze Type` 英文 **5 个选项**，**只对得上 4 个**——剩下那一对（`可登录和充值，不可投注和提款` vs `[5] Login allowed, betting allowed, no deposit, no withdraw`）**在投注与充值两个维度刚好相反**，而这两个维度都直接管钱。<br>⚠️ **也可能不是冲突**：`[1][2][3][5][7]` 的跳号很像位元遮罩，没证据之前不推。<br>💡 **同批把字典两处 §4 值域缺口结掉**（`ruling:R-133`）。<br>**22 条：20 已结 ／ 2 挂账 ／ 0 未结**）。<br>🔴 **`C-022` 当日结**（`ruling:R-138`）：**中文翻错了**，`投注` 与 `充值` 对调。Luke 亲自跑线上，三件同时成立（`Freeze Type` 是 `[5]` ／ 进得了游戏下得了注 ／ 充值被挡）。改中文已纳入需求 `30`。v0.14 · 2026-08-28（✅ **`C-021` 当日开、当日结为「不成立」**（`ruling:R-115`，Luke 逐字「**这个忽略即可，我的截图是 PRE 环境的**」）：与 `C-018` 同一个理由。<br>⚠️ **同一个坑第二次，但这次没踩下去**——照 `R-099` 的教训只问了一句、没自己判环境，所以没有再造出一条假冲突。<br>**21 条：19 已结 ／ 2 挂账 ／ 0 待裁**）。v0.13 · 2026-08-28（🆕 **新增 `C-021`** 🔴 待裁，触发源需求 `29`：Luke 传来的两张**线上下拉展开**截图里有 `30002 - uhiguymapces`，而 `ruling:R-099` 判它是 `PRE` 测试建的、`PROD` 没有（`C-018` 据此判不成立）；其中一张页脚写 `SQL Info: Not available in production environment.`。<br>🔴 **本条刻意不下判断，只问一句「这两张是 `PRE` 还是 `PROD`」**——照 `R-099` 自己的教训。<br>💡 **同批带进一件实情**：线上下拉共 **12 项**（`All` ＋ 11 个实体站），显示格式是 **`ID - Name`**、ID 由小到大。<br>**21 条：18 已结 ／ 2 挂账 ／ 1 待裁**）。v0.12 · 2026-08-28（🆕 **状态表补第四种 `📌 挂账`**：已裁定「刻意不改」——问题成立也查证到位，但这一轮不动手，**必须写死触发条件**，不写就等于永远没人回来看。<br>🔴 **`C-019` `C-020` 由 待裁 改 挂账**（Luke 2026-08-28 逐字「不用改动其他需求的档案」「如果之后有需要更新或我要做到知识库和总入口的时候，再来调整就好」）：两条合并写了一段共同处置——**改哪三处的清单** ＋ **三个触发条件** ＋ **根因**（那份档是「轮播图需求的 PRD」，把注册登录基线抄进去当附录，抄一份就会漂）。<br>**20 条：18 已结 ／ 2 挂账 ／ 0 待裁**）。v0.11 · 2026-08-28（🆕 **新增 `C-020`** 🔴 待裁：注册页两个 placeholder 逐字与线上不符（档案 `Phone Number` ／ `Verification code`，线上 `Mobile Number` ／ `Enter your OTP`）。**与 `C-019` 同一族、同一份档**——`rJDiZMtfzl` 的「已上线基线，本版一字未改」只保证「本版没动它」，不保证「它跟线上一致」。**20 条里 18 条已结、2 条待裁**）。v0.10 · 2026-08-28（🔴 **`C-018` 当日开、当日结为「不成立」**（`ruling:R-099`）：那张 F12 是 **`PRE`**，`uhiguymapces` 是 `PRE` 测试建的，`PROD` 没有。<br>🔴 **`C-017` 与 `C-018` 是同一个根因造出来的两条假冲突：我把两个环境的数据当成同一个。** ⇒ 教训写进 `R-099`：**同一轮拿到多张截图，先逐张问「这是哪个环境」再交叉比对**。<br>**19 条里 18 条已结，只余 `C-019` 待裁**）。v0.9 · 2026-08-28（🔴 **`C-017` 再更正为「不成立」**：新证据（F12 的 `settings` 接口）显示 `30002` **解析得出名字、是个禁用中的站**，不是查无此站——我拿一张有排序规则的列表截图当全集，**排序规则就在手边没拿来验**。`ruling:R-092` 那两条防呆仍要做，但理由改为「防呆」而非「已有坏数据」。<br>🆕 **同批新增两条**：`C-018` 🔴 待裁（迭代上线那刻，一个叫 `uhiguymapces` 的禁用站会直接显示给玩家；`G1` 不许改名 ⇒ 只能移出配置或新建）／`C-019` 🔴 待裁（`doc:hackmd/rJDiZMtfzl` §7 说「置灰」，线上实况是「过滤掉」——**差别正好是本需求要做的那件事**，照档案读会低估工作量）。**19 条里 17 条已结、2 条待裁**）。v0.8 · 2026-08-28（`C-017` **当日开、当日结**（`ruling:R-092`）：**后台保存时校验 ＋ 后端解析时静默跳过**，两条缺一不可——实体站不做删除，坏 ID 不会自己消失。**17 条全部已结**）。v0.7 · 2026-08-28（🆕 **新增 `C-017`** 🟡 待查：`phstore_show_id` 两栏都配了 `30002`，而实体站管理线上只有 `1`~`10`；**「解析不到的 ID 怎么办」没有任何档写过**，而 `PRD_v1.3_phStoreMgmt` §5.2 刻意让这情况能发生且无提示。触发源：需求 `27.注册可选实体站展示`）。v0.6 · 2026-08-26（`C-016` **当日已裁**（`ruling:R-059`）：那 4 栏是**在建功能、`PRE` 测试中**，要写；连带更正 `HOWTO §六` 第 6 条——`PRE` 截图的**结构**也不一定等于线上现况）。v0.5 · 2026-08-26（新增 `C-016`）。v0.4 · 2026-08-22（新增 `C-015`，当轮结掉；**15 条全部已结**）

---

## 读法

每条三段写：**A 线上写什么 ／ B 档案写什么 ／ C 冲突在哪＋什么场景会炸**。
一行摘要看不出是整条打架还是半句打架，所以不写一行摘要。

| 状态 | 意思 |
|---|---|
| 🔴 待裁 | 两边都有依据，需要人拍板 |
| 🟡 待查 | 只有一边有依据，另一边要再确认 |
| ✅ 已结 | 已裁定，处置写在该条末尾 |
| 📌 挂账 | 🆕 **已裁定「刻意不改」**——问题成立、也确认了，但这一轮不动手。<br>🔴 **必须写死触发条件**（什么时候回来改）。不写就等于永远不会有人回来看 |

### 🆕 什么**不**进这份档

> Luke 2026-09-05 裁定（`ruling:R-196`）。

🔴 **发布落後不是冲突。** 档案是对的、只是还没传上去 —— HackMD 上还是旧版、
Cloudflare 还没重传、总入口还没重生 —— **两边没有打架，也没有任何规格要裁**。
那是**待办没做**，落点是 [`HOWTO.md`](HOWTO.md) `§七` 的待办清单。

⚠️ **界线在档头那句**：「**线上后台才是现况**」—— `C-NNN` 收的是
**线上后台的行为或规格**与档案打架，不是「任何线上的东西与档案不一样」。

**触发源**：`writeback_review.py` 连三轮要求把「HackMD 曾是 `v1.9` 之前的旧版、
而本地是 `v1.9`」登记成 `C-NNN` —— 照当时那条配对规则的字面它判得对，
**是规则写太宽**。已收窄，见 [`../_tools/codex_gate/prompt_writeback.md`](../_tools/codex_gate/prompt_writeback.md)。

---

## `C-001` · 代理线注册白名单 ✅ 已结 —— **不是冲突，是我读错了中文**

**结论先写**：**没有配置 ＝ 全部不允许自助注册。** 与 `prd:PRD_v1.5_agentLineWhitelist.md` 红线 `G4` 一致，**两边没有冲突**。
出处：使用者 2026-08-19 逐字「没有配置，就是全部不允许自助注册」。

### 我为什么读错

后台 `配置描述` 第 3 条原文：

> 3．暂无一个配置，可以全部开放注册。

我把逗号当成条件句的断点，读成「**若**一个配置都没有，**则**可以全部开放注册」。

正确的读法是把「暂无」的宾语一路吃到底：

> 暂无〔一个可以全部开放注册的配置〕

＝ **系统没有「一键全开」这个东西。** 要开谁就得逐条配进白名单。

第二份证据（当时就在手上，我没去查）：
`prd:PRD_v1.4_agentLineWhitelist.md` v1.2 版本记录写着「**只分配开启、无全开**」——
和这条描述讲的是同一件事。

### 教训

| # | 教训 |
|:-:|---|
| 1 | **中文断句歧义会造出假冲突。** 我拿一句可两读的话去撞 PRD 红线，撞出一条根本不存在的冲突 |
| 2 | **手上就有第二份证据没去查。** 「只分配开启、无全开」一句就能挡下这次误判 |
| 3 | 🔴 **报冲突前，先在同一份 PRD 里 grep 一次相关字眼**，别只比对单句 |

⇒ 已写进 [`README.md`](README.md) 的写作纪律。

**处置**：✅ 已结。**不需要改任何档。**

---

## `C-002` · KYC 触发节点配置有一笔不符格式 ✅ 2026-08-20 已结（是测试配置）

**A · 线上后台写什么**

`kyc_checkpoint` 规定的格式（后台 `配置描述` 原文）：

```
配置格式：代理:节点,代理:节点
```

`BRAND_A` 栏的实际值有 7 笔，其中一笔**没有 `:节点`**：

```
… agent04@BRAND_A:2, agent05@BRAND_A, agent06@BRAND_A:1 …
                     ^^^^^^^^^^^^^^^ 缺 :节点
```

出处：`shot:基本配置`（使用者 2026-08-19 补拍）

> ⚠️ **这是肉眼从截图读的，不是 OCR。** 值得先回后台核一次再往下走。

**B · PRD 写什么**

`prd:PRD_v1.11_KycCheckpointConfig.md` **写得很完整**，不是缺口：

| 出处 | 写了什么 |
|---|---|
| §2.3.1.2 | **某一组格式错误 → 只有那一组不生效**，回到现行 KYC 流程 |
| §2.1 | 空白字符即格式错误（半角与全角都算），不做 trim；末项带逗号也算错 |
| v1.11 ③ | 解析改「一组一组看」，坏的那组不生效，**其余不管排前排后一律照常生效**（废止旧版「遇错即止」）|
| `AC54`／`AC81` | 逐条验收，含「脏数据绕过校验进库」的情形 |

节点枚举也对得上：PRD §52 写「取值只有 `1`（全程免 KYC）与 `2`（提款前校验），`0` 非法」，
与后台 `配置描述` 的「1：全流程不用 KYC／2：提款前才 KYC」**一字不差**。

**C · 所以这不是规格缺口，是线上数据异常**

我原本判成「规格可能没写」，**判错了方向**。改判如下：

| | |
|---|---|
| 规格 | ✅ 有写，而且 v1.11 特地反转过口径来处理这件事 |
| 线上 | 🟡 有一笔值不符格式 |
| 后果 | 照 §2.3.1.2，**第 5 笔那一组不生效**，该代理线回到现行 KYC 流程 |

🔴 **不是事故，但是一笔「配了等于没配」的死值。**
运营以为设了，实际没生效——这种沉默失效，后台没有任何提示。

**要做的两件**：
1. 请使用者回后台确认那一笔的原值（我是肉眼读截图，可能读错）
2. 属实的话，这是**运营侧要清的脏数据**，不是要改的规格

> 顺带一条可考虑的改进：`AC81` 已经处理「脏数据绕过校验进库」，
> 但**没有任何东西会告诉运营「你这组没生效」**。要不要加提示，是新需求，不在本档判。

---

**处置**：✅ **2026-08-20 已结——不必回后台，那是测试配置。**

使用者 2026-08-20 逐字：

> 「截图的是已经开始进行测试了，所以有各种配置去看是否生效」

同日追问「是哪个环境、是不是同一次拍完」，答：

> 「PRE」「同一个环境全部拍完」

⇒ 那笔缺 `:节点` 的值**是 `PRE` 上人为填的**，用来看配置生不生效。
**不是生产脏数据，没有要清的东西，规格也没有要改的东西。** 上面 A / B / C 三段的分析都成立，
只有「后果」那一段的前提不成立——它假设了这是生产值。

🔴 **连带影响一件事**（不是本条，但同一张截图）：

`shot:基本配置` 那张图拍的是 **`PRE`**，不是生产。
[`enums/base_config_items.md`](enums/base_config_items.md) §三 据「品牌栏用的是改号后的 `1`/`2`」
推出「**这一版已经上线了**」——**`PRE` 有 ≠ 生产有，这个推论的前提站不住**，2026-08-20 改标 `❓ 待确认`。

✅ **2026-08-21 问到答案，该推论证实是错的。** 使用者逐字：

> 「**还没上线，还在 pre 环境测试中**」

⇒ **`KycCheckpointConfig` 未上生产。** `❓` 结案，`base_config_items.md` v0.3 已回写。
🔴 **这是「结构可信、值只代表 `PRE`」这条判准第一次拿到反例验证**——
当初若照原推论写进 PRD 的「平台既有事实」，会把一个没上线的功能当成既有能力去复用。

📌 **可复用的教训**：**105 页全部拍自 `PRE`，同一个环境一次拍完** ⇒
**结构可信（栏位 / 按钮 / 菜单 / 后端模板档名），值只代表 `PRE`。**
「某功能已经上线」这类推论一律推不出来。判据表见 [`graph/GAPS.md`](graph/GAPS.md) §一之一。

---

## `C-003` · 线上有活动模板，Axure 原型没有 ✅ 2026-08-20 已补

**A · 线上**：`活动管理列表 ＞ 添加` 下拉有 `type=85 下载APP活动(BRAND_A)`，
账变类型也有对应的 `otid=456 Download App Bonus`。两份独立证据。

**B · 档案**：`02_BO_需求分类.md`（当时 136 单元，v2.4 后 165）／`01_BO_目录清单.md`／`PHPL_Axure原型_目录索引.md`
**三份 grep 全无**。

**C · 冲突在哪**：这不是打架，是**缺口**。
使用者 2026-08-19：「因为当初这个活动不是我做的，所以这个需求原型不在我这里，之后我要补上」。

🔴 **值得记的是发现方式**：这种「线上有、原型没有」的缺口，
**翻 Axure 永远查不到**——你不知道自己不知道什么。只有比对线上后台才会浮出来。

**处置**：✅ `02` v2.4 已在 §四之二 165 新增单元 `下载APP活动`（`P`）。

✅ **2026-08-20 原型已入库。** 使用者给了链接 `https://nj2nwp.axshare.com/`，
并交代「**这份不是我做的，不知道作者什么时候会关闭链接**」⇒ 当场抓存，不等。

| 落在哪 | 内容 |
|---|---|
| `_raw/axure_nj2nwp/_sitemap.json` | 23 节点 / **13 页** |
| `_raw/axure_nj2nwp/0NN_*.json` | 13 页正文（`visible` / `hidden` / `notes` / `links`）|
| `_local/axure_nj2nwp/images/` | **171 张原图**（7.3 MB）＋ 102 张的 OCR `.txt` / `.tsv`。🔴 **不进 git**，同 `_local/` 既有口径 |
| 🆕 `_local/axure_ck7zdd/images/下载app活动/` | **8 张截图**（svg 外壳内嵌 png，两种都存）＋ 8 张 OCR。🔴 不进 git |

🆕 **2026-08-20 · 上游换成自家的站（使用者说明 ＋ 当场抓存核对）**

使用者：「`nj2nwp` 是另一个产品做的所有需求，**现在不需要了**，所以我只是把下载 APP 活动的部份，
直接截图放到了 `ck7zdd`。」⇒ 图的上游由**别人的站**改为**他自己的站**（`ck7zdd`「活动模版 / 下载APP活动」，1 页 8 张）。

**8 张逐张比对过，涵盖 11 / 13 页**：

| ck7zdd | 内容 | 对应 nj2nwp |
|:-:|---|---|
| u1 · u2 | H5/官网下载引导 ＋ 个人中心 `Download` 入口 ＋ iOS 信任企业级 APP 六步 | `首页` |
| u3 | 首次 app 登录弹奖金框（`₱88` / `Complete KYC to Claim`）| `首页_1` |
| u4 | APP 端按钮三态 `KYC Verify` / `Claim` / `Received` / `Claimed` ＋ H5 说明页 | `下载app活动_1`、`下载app活动` |
| u5 | UserList 新增 `APP初次登录时间 (First App Login)` | `userlist` |
| u6 | 活动派奖记录（`自动/Auto`、`88.00`、流水 `2,000`）| `活动派奖记录` |
| u7 | 活动管理列表「增加【下载app活动】选项」| `活动管理列表` |
| u8 | 后台配置页（参与条件 `首次登录app` / 派发 `88` / 流水 `2,000`）| `下载app活动_2` |

🆕 **u3 多给了一样先前没记的**：账变类型 **`[+] Download APP Bonus`**（`BalanceRecord–Promo` 生成实时账变记录）。

🔴 **两页 ck7zdd 上没有，使用者 2026-08-20 明确说不补**：

| 页 | 内容 | 现况 |
|---|---|---|
| `kyc验证页` | KYC 页三处 `Upload…` 文案改写 | **只有文字**（`_raw` 的 JSON 在 git），**无图可回核** |
| `首页_2` | 后台首页加另一品牌后台入口，点击新开 Tab 须带登录信息 | 同上 |

⚠️ 这两页的原图只存在于 `_local/axure_nj2nwp/`（不进 git、上游已失效）⇒ **那批不要删**。

🔴 **图（`_kb/graph/`）一个字都没改，理由如下**——
先前打算把 13 个 `axure:nj2nwp/*` 节点改指 `ck7zdd`，**查完发现不能做**：
`build_graph.py` 的 `axure:` 节点是按 `_raw/axure_<站>/` 的**页**建的，而 ck7zdd 这边**只有 1 页**；
写边时又按 `(src, rel, dst)` 去重 ⇒ 12 条 `实作于` 边全部指向同一个节点会**被压成 1 条、丢掉 11 条证据文字**。
而且节点名 `axure:nj2nwp/*` 指的是**正文 JSON 的来源**，那确实是 nj2nwp、且已永久存在 git 里，**名字本来就是对的**。
⇒ **只换素材来源、不动图。**

🔴 **13 页是同一个需求，不是「3 页本条 ＋ 10 页别的」。**
这份原型整份就是 `下载APP活动`，**它跨了 10 个既有页面各改一处**——
读完才看得出来，一页一页看会误判成一堆零散页。

**A · 这个活动本身（3 页，三端各一）**

| 页 | 端 | 抓到什么 |
|---|---|---|
| `下载app活动_2` | **后台配置** | 参与条件 `首次登录app`／派发彩金 `₱88`／流水要求 `2000`；说明三条（自动派发、同帐户只派一次、流水 ≥2000 才可提）；🔴 **「自动参与 ＋ 手动领取」写死不可调整** |
| `下载app活动_1` | **APP 端** | 按钮三态 `Claim` / `Received` / `Claimed`；未完成 KYC → 点击跳 KYC 认证页；已完成 → 可直接领；**H5 与 APP 未登录一律隐藏该按钮** |
| `下载app活动` | **H5 说明页** | 「只需要增加活动说明页面，无需展示领取奖金按钮」 |

**B · 它连动到的既有页面（10 页，每页一处改动）** ⇒ 这就是一张现成的连动清单

| 页 | 面 | 改什么 |
|---|---|---|
| `首页_1` | APP 首页 | **首次**经 app 登录弹奖金框：`Welcome Bonus for Your First App Login`／`₱88`／`Complete KYC to Claim`；已完成 KYC 可直接领、未完成点 `KYC Verify` 跳认证页 |
| `首页` | H5 / 官网 | 下载 APP 引导，含 iOS 信任企业级 APP 的五步（`General → VPN&Device Management → Device Options → Trust Device`）|
| `活动` ／ `活动_1` | 前台活动列表 | 列表加一个 `下载app活动` 入口（两端各一份）|
| `kyc验证页` | H5 KYC | **文案变更**：三处 `Upload …` 改写（原型上写着「把文案改成：」）|
| `活动管理列表` | 后台 | 「增加【下载app活动】选项」——对应线上 `type=85` |
| `活动派奖记录` | 后台 | 该活动的派奖记录行：`自动/Auto`／`88.00`／流水 `2,000`／`已领取 Claimed`／`已发 Verified`／备注 `自动出款通过` |
| `userlist` | 后台用户列表 | **新增栏位** `APP初次登录时间 (First App Login)`，格式 `YYYY-MM-DD HH:MM:SS` |
| `首页_2` | 后台首页 | 加**另一品牌后台**的入口：点击新开 Tab，**须带入本系统的登录账号信息**。<br>⚠️ 原型上写的是品牌真名；**本库没记过两个品牌与 `BRAND_A` / `BRAND_B` 的对应关系**，所以这里不指定是哪个 |
| `提示` | 通用弹窗 | 顶号提示（`logged in on another device`）——**与本活动的关系未确认**，可能只是共用素材 |

⚠️ **三件要知道的**：

1. **数值一律回原图**——`₱88` / `2000` / `88.00` 是 OCR 读出来的，本库既有口径是「结构可靠、数值不可靠」
   （实测 `759.7500` 会读成 `159./500`）。写进 PRD 前回 `_local/axure_nj2nwp/images/` 对一次。
2. **`userlist` 那条栏位是真连动**——`APP初次登录时间` 是这个活动的判定依据（「首次经 app 登录」），
   动它会波及用户列表。这类边正是图要抓的。
3. ✅ **13 页已接进图**（2026-08-20）——`build_graph.py` 加 `load_axure_sites()`，
   凡 `_raw/axure_*/` 一律建成 `axure:<站名>/<页名>` 节点（**站名隔开命名空间**，
   两份原型都有 `活动管理列表`，不隔会合成同一个节点）。
   **脚本只建节点不连边**；「哪一页动到谁」是判断，走 `graph/edges_manual.tsv` §⑤，18 条各带出处。
   ⇒ 现在 `python3 _tools/graph_query.py 下载APP活动 --hops 2` **两跳就吐出完整连动清单**（19 个节点）。
   🔴 `axure:nj2nwp/提示`（顶号弹窗）**刻意不连**——与本活动的关系未确认，判不出来就不连。

---

## `C-004` · `02` §五 漏列 `客户端金刚区管理` ✅ 已结

**A · 线上**：`运营管理` 底下有 `客户端金刚区管理`（截图已确认）。
**B · 档案**：`02_BO_需求分类.md` §五「现实后台二级目录逐项判定（72 行）」**没有这一行**。
§四 **33** 有对应的 Axure 单元 `客户端金刚区管理`，归在「运营管理」。

**C · 冲突在哪**：§五 那张表自称是**现实后台的完整二级目录**，但漏了一项。

**处置**：✅ `02` v2.4 已补为第 73 行，标题由「72 行」改为「73 行」。
其余 72 项已用 105 页截图逐一比对过，无第二处漏列。

---

## `C-005` · 活动模板：设计稿有、线上没有 ✅ 已结

**A · 线上**：`添加` 下拉 15 个模板，**没有**九宫格／大转盘。账变类型也没有对应项。
**B · 档案**：`02` §四 16 有 `Grid Promo Engine_九宫格活动`，且 `待评审/08.元旦转盘/Archive/PRD_v2.3_newYearWheel.md` 已写完 PRD。

**C · 冲突在哪**：不是冲突，是**排期**。

使用者 2026-08-19：「九宫格还没做到，排期中」。
同批另一条：`type=96 开宝箱活动PHPL` 在下拉里，但账变类型没有对应 bonus ⇒ 「开发中，尚未提测」。

🔴 **另有一条口径要回写**：§四 6 `新每日存款抽奖活动` **就是** `newYearWheel`——
使用者：「每日存款抽奖活动，这个就是大转盘的前端形式」。
`otid=300 Lucky Wheel Bonus` 是第二份证据。

**处置**：✅ 已确认。回写 `02` §四 的动作记在
[`enums/campaign_template_type.md`](enums/campaign_template_type.md) §三，五条一起改。

---

## `C-006` · `BalanceRecord` 的 `Summary` 把一笔提款算两倍　✅ 已结 —— **不外溢**

**A · 线上看到什么**

筛一个会员、一天、只选 `26`／`27`／`28` 三型（`shot:BalanceRecord`，使用者 2026-08-19）：
`[-]Withdraw Applied` 与 `[=]Withdraw Success` **各记一次 `Cash out -999.00`**，
`Summary: Funds movement on this page` 印 **-1,998.00**。实际只提了 999。

**B · 使用者给的口径**（2026-08-19）

> 「充值提款类、活动类，都会读取这里，比方说汇总报表里的充值，就只有读取账变 id=31 这个 online deposit 的类型」
> 「**提款只读 `28 Withdraw Success`**」

**C · 结论：只影响 `BalanceRecord` 页内的 `Summary`，不外溢到下游报表**

| | 读哪些 `otid` | 会不会双计 |
|---|---|:-:|
| 汇总报表 · 充值 | 只读 `31` | ❌ |
| 汇总报表 · 提款 | **只读 `28`** | ❌ |
| `BalanceRecord` 页内 `Summary` | 使用者当下勾选的全部 | ✅ **会** |

🔴 **`BalanceRecord` 的 `Summary` 是「本页勾选条件的加总」，不是业务口径的充提合计。**
运营若拿它当充提数字用，提款会翻倍。**这是使用方式的问题，不是缺陷。**

### 两条口径要登记进字典

⇒ [`PRD_Spec/90_field_dictionary.md`](../PRD_Spec/90_field_dictionary.md) 现在**没有任何字段写明「由哪些 `otid` 组成」**。

| 口径 | 内容 |
|---|---|
| 汇总报表 · **充值** | ＝ `otid 31` Online Deposit。**不含人工充值**（`38`／`52`／`23` 都不算）|
| 汇总报表 · **提款** | ＝ `otid 28` Withdraw Success。**只算已成功的**，申请中（`26`）不计 |

**处置**：✅ 已结。待办 ⇒ 两条口径写进 `90_field_dictionary.md`。

---

## `C-007` · `CommissionRecord` 判 `R` 是错的 —— 它会派钱　✅ 已结

**A · 线上看到什么**（`shot:CommissionRecord/u0`・`u1`）

顶部三个按钮：

| 按钮 | 对应账变类型 |
|---|---|
| 持续发展奖金／`Agent Growth` | `otid 455` Agent Growth Bonus |
| 里程碑奖金／`Agent Achievement` | `otid 454` Agent Achievement Bonus |
| **批量派发／`Batch Distribute`** | `otid 323` Commission |

列表有**状态机**与**操作**：

| 状态 | 操作 |
|---|---|
| `待处理/Pending` | `派发/Distribute` ／ `重跑/ReRun` |
| `已派发/Distribute` | 两个操作都灰掉 |
| `滚存中/Accumulating` | `重跑/ReRun` |

另有 `派发人/Admin`、`派发备注/Remarks` 两栏留痕。日期区间以**半月**为单位（`1st half`／`2nd half`）。

**B · 档案写什么**

[`02_BO_需求分类.md`](../站点盘点/02_BO_需求分类.md) §五 30 判 **`R`**，依据栏写「✅ Luke 2026-08-14 确认」，
对应 §四 62 `佣金报表`（也判 `R`）。

**C · 冲突在哪**

`R` 的定义是「对既有数据做**只读查询**——**页面上没有任何会改数据的操作**」。
但这页会**派钱**，还有三态状态机和操作人留痕。**判 `R` 与定义直接抵触。**

### 该判什么，我给不出唯一答案 —— 两个候选

| 候选 | 理由 | 疑虑 |
|---|---|---|
| **`W`** 审核工作流 | 有待处理队列、要人操作才落账、有操作人留痕 | 动作叫「派发／重跑」，**没有「审核／驳回」**，不是典型审核闭环 |
| **`P` 的 `R-子`** | 与 `运营管理/代理策略`（§五 72，判 `P`）**共用 `user/commission/` 模块**。<br>结构类似「活动管理列表（`P`）＋ 活动派奖记录（`R-子`）」 | `R-子` 依定义是**记录报表**，不该有派发动作 |

### ✅ 裁定（使用者 2026-08-19）

| 问 | 答 |
|---|---|
| 佣金派发有没有审核？ | **「没有审核」** |
| 跟 `代理策略` 是不是一个需求的两半？ | **「是的」** |

⇒ **不判 `W`**（没有审核闭环）、**不判 `R`**（会派钱）。
**主挂 `P`**（派奖那套：派发时点、幂等、重跑、留痕），**加挂 `R`**（它同时是有筛选／导出／合计的报表）。

**处置**：✅ 已结。`02_BO_需求分类.md` v2.4 已回写：
§四 62 与 §五 30 改判 `P ＋ R`、§四 31 `代理策略` 加注、新增 §三-9 写明两者是同一需求的两半。

---

## `C-008` · `UserList` 拆不拆　✅ 已结 —— **修订原裁定，逐个放行**

**A · 既有裁定写什么**

[`02_BO_需求分类.md`](../站点盘点/02_BO_需求分类.md) §三-7 标题就是
**「`UserList_用户列表` ＝ `M`（单挂，**不拆**）」**，版本记录 v2.1 记为 Luke 裁定。三条理由：

| # | 理由 |
|:-:|---|
| 1 | 重的操作 **Axure 自己已经拆成独立页了**——`Freeze`／`ManualDeduction`／`CreateAccount`… |
| 2 | 剩下没被单独画过的（**踢出／修改用户手机号／钱包地址解绑／设置会员风控标签／一般备注**）就是列表行内的小动作，`MDM-009` 收编 |
| 3 | 没有人会一次改整页；为 `UserList` 出整页 PRD 违反「一个需求只出一份档案」 |

**B · 我 2026-08-19 的 `G-1` 建议**

拆 5 个成独立单元：`ManualDeposit`／`AccountInfo`／`TurnoverAmount`／`Password`／`SendMsg`。
使用者当轮回覆「`G-1` 表我同意」。

**C · 冲突在哪**

🔴 **我提 `G-1` 时没有读 §三-7，使用者同意时可能也没有回头对这条。**
两边逐条比对：

| 页 | §三-7 怎么说 | 我的建议 | 判定 |
|---|---|---|:-:|
| `KickOut` | 明列为「小动作」 | 并入 | ✅ 一致 |
| `InternalNote`（一般备注）| 明列为「小动作」 | 并入 | ✅ 一致 |
| `PromoCode` | 属「小动作」类 | 并入 | ✅ 一致 |
| `AgentTeam` | 未提 | 并入 `UserInfo` | ✅ 不抵触 |
| `Unfreeze` | 未提 | 并入 `Freeze` | ✅ 不抵触 |
| **`SendMsg`** | 🔴 **裁定自己留了问号**，并给判据：「有没有受众、下发时机、已读态」 | 独立 | ⚠️ **判据全中，见下** |
| **`ManualDeposit`** | 理由 1 的逻辑是「重的 Axure 已拆」——**但 Axure 没画它** | 独立 `W` | 🔴 **抵触** |
| **`AccountInfo`** | 只提「钱包地址解绑」**一个动作** | 独立 `M` | 🔴 **范围不同** |
| **`TurnoverAmount`** | 未涵盖 | 独立 `M` | 🔴 **裁定未涵盖** |
| **`Password`** | 未涵盖 | 独立 `M` | 🔴 **裁定未涵盖** |

### 逐条我的看法（供裁定，不代表结论）

**`SendMsg` —— 裁定的判据指向「独立」。**
§三-7 写：「判据是『有没有受众、下发时机、已读态』——有 ⇒ 那才是真正的通知类」。
`shot:SendMsg` 实证：**6 种接收范围**（受众，含红字「发送所有会员」全站广播）、
`发送消息` 按钮（下发时机）、已读态在 `prd:PRD_v1.3_bottomNavMessageCenter.md` 有 `is_read`。
⇒ **三项全中。裁定自己说这种要独立。**

**`ManualDeposit` —— 理由 1 的前提不成立。**
「重的操作 Axure 自己已经拆成独立页了」——**Axure 漏画了 `ManualDeposit`。**
但 [`02_BO_需求分类.md`](../站点盘点/02_BO_需求分类.md) §五 17 有「审核(人工充值)」，
与 §四 45 `ManualDeduction`（判 `W`）**完全对称**。
⇒ **一个判 `W` 独立、另一个并进 `M`，两边不一致。**

**`TurnoverAmount`／`Password`／`AccountInfo` —— 裁定当时没有这三页的资料。**
v2.1 裁定时手上只有 Axure 与 26 张截图；这三页是 2026-08-19 这批 386 张才拍到的。
`TurnoverAmount` 尤其：它**没有审核却直接决定能不能提款**（使用者 2026-08-19 确认）。

### ✅ 裁定（使用者 2026-08-19）

> 「逐个放行，是不是更合理，如果是，那就走这个方案」

**⇒ 逐个放行。5 个全部独立。**

### 判准（已写进 `02_BO_需求分类.md` §三-7 v2.4）

🔴 **我第一版把判准写成「一个单元只能挂一套主规格档」——错的。**
使用者 2026-08-19 当场纠正：「其实我们没有一定只能挂一个规格档，这个我们先前讨论过了我记得？」
`02_BO_需求分类.md` §三 整节标题就是「**要挂多份 spec 的清单**」，
`M ＋ W`／`P ＋ M`／`W ＋ S` 都有先例。**加挂是常态，不是例外。**

修正后的判准：

> **这个操作有没有自己的完整闭环？有 ⇒ 它值得自己一份 PRD ⇒ 独立成单元。**

**收编的代价不是「挂不到第二份 spec」，是「它永远不会有自己的 PRD」**——
收编后它只是 `MDM-009` 操作列里的一行，
而没有人会为了写「人工充值」去写一份「`UserList` 整页 PRD」（原裁定理由 3）。

`ManualDeposit` 有**发起 → 待审 → 审核 → 落账**的完整闭环，与 `ManualDeduction`（已判 `W`）对称。

> 📌 **这次纠正本身值得记**：结论没变（逐个放行），但**理由变了**。
> 理由不同，下一份档的行为就不同——若照我原本的错理由，
> 以后会误以为「加挂不能用」，把该加挂的都拆成独立单元。

### 🔴 但原裁定的理由 3 完全保留

> 「没有人会一次改整页。PRD 是按需求写的，不是按页面写的。」

**拆的是「单元」，不是要写一份「`UserList` 整页 PRD」。**
这句仍然有效，`02` §三-7 原文保留未动。

⇒ **这次是修订，不是推翻。** 原裁定的三条理由里，理由 3 不动，理由 1／2 补上判据后收窄适用范围。

**处置**：✅ 已结。`02_BO_需求分类.md` v2.4 已回写（§三-7 修订、§四之二 `160`–`164` 定案、§一 合计 165）。

---

## `C-009` · 开宝箱：原型已拿掉「活跃条件周期」这个控件，PRD 还把它列为必填配置 ✅ 2026-08-21 已结

**A · Axure 原型写什么**（`ck7zdd` `mystery_chest______`，2026-08-21 抓）

§2 参与门槛区**只有两个控件**：`*活跃条件：` 与 `*活跃天数：`。**没有任何周期下拉框。**
全页只有一个 `周期` 控件，在 §1 基本信息，选项 `周` / `月` / `整个周期`（无 `日`）。

站上版本记录 `v1.146`（2026.08.12 · Luke）逐字：

> `Mystery Chest_开宝箱活动`：限定主周期只能用周；去除门槛条件周期，写死为日。

**B · PRD 写什么**（`prd:PRD_v1.10_mysteryChest.md` §3.2 M2-A 字段表第 1 行）

| 字段 | 类型 | 必填 | 边界值 |
|---|---|---|---|
| 活跃条件周期 | Enum | 必填 | 本活动固定**日**（每日重判） |

**C · 冲突在哪 ＋ 什么场景会炸**

**值不冲突**——两边都是「日」。冲突在**它还是不是一个配置项**：
PRD 把它写成 `Enum` ＋ `必填`，字段表的读法就是「运营要在后台选一个值」；
原型上运营根本选不到，因为控件已经不在了。

会炸的场景：**开发照 §3.2 字段表施工**——建一个 `active_cycle` 的 Enum 字段、
前端渲染一个下拉框、后端做必填校验。做完与原型对不上，评审时才发现，整块返工。
测试同理：照 `必填` 去构造「不填该怎么报错」的用例，界面上找不到那个控件。

**🔴 这条是怎么漏掉的**（判据本身要记）

`PHPL_Axure原型_目录索引.md` 的比对是**按页数与页名**做的。
`v1.146` 改的是**页面内容**，页没增没减、名字没变 ⇒ **目录树比对一个字都不会说**。
`_kb/HOWTO.md` §七 原本只列了三份要回核的 PRD（`case:20` / `22` / `23`），
正是因为那三页是**新增页**、目录树看得见；`mysteryChest` 看不见，所以没被列进去。

⇒ **判据改为：以站上版本记录（`--changelog`）为准，不以页数差为准。**
已写进 `_tools/scrape_axure_sitemap.py` 的档头与 `--check` 输出。

**✅ 处置（Luke 2026-08-21 裁定，选 ㈠）**

Luke 逐字：

> 「这个跟开发讨论后，已经拿掉了，不需要了，已经直接写明了用 `活跃天数`，
> 这个就是日周期的意思；并且，第一版也不做周、月等周期」

⇒ **不是原型漏画，是这个配置项本来就已经取消掉了。** PRD 是落后于现况，不是原型落后于 PRD。

**已做**：`PRD_v1.10_mysteryChest.md` → **`PRD_v1.11_mysteryChest.md`**（2026-08-21）

- §3.2 M2-A 字段表**删去「活跃条件周期」整行**。
- 「判定周期写死为日、不是配置项、`活跃天数` 这个字段名本身就是日周期的意思」写进 §3.2 导语，
  并补上「**本期不做周 / 月等其他判定周期**」。
- **口径一字未改**——判定周期仍是日、仍每日重判。
- ⚠️ **§3.1 M1 的「主周期」不动**：那个控件还在（选项 `周` / `月` / `整个周期`），
  后端仅允 `WEEK`（`V15`）的规则不变。**两个「周期」是两回事，别一起删。**
- `lint_prd` **0 失败 0 告警**；引用面 4 份档共 8 处已同步改名
  （`OPEN_POINTS` 4 ／ `_cases/README` 2 ／ `PRD_Spec/README` 1 ／ `HANDOFF` 1）。
  🔴 `HANDOFF.md` 那处**只改 href、显示文字仍写 `v1.10`**——那一行记的是「当时量到什么」，不是指路。

**🔴 本条留下的判据，比这次的改动重要**：

> **字段表是施工面。** 写成 `Enum` ＋ `必填`，开发就会去建字段、渲染下拉框、做必填校验。
> **一个写死的值不该出现在字段表里**——要写就写进导语，讲清楚它为什么不是配置项。

⚠️ 这条只由本次一个样本支持，**尚未量过全库还有几处同样写法**。要不要升成条款，等第二个样本。

---

## `C-010` · 7 条 `RPT` 条款的依据是**别家平台的文档**，其中 1 条已证实与本平台相反 ✅ 2026-08-21 已裁

**A · 线上现况写什么**（Luke 2026-08-21，逐字）

> 返水**一天一次，凌晨 5 点去统计昨天的**，然后**先跑升级再跑奖励**

⇒ **先 VIP 升降级，再跑返水奖金**，即按**升降级后**的等级算返水。

**B · 档案写什么**（`PRD_Spec/02_prd_spec_report.md` §4 第 14 项 ／ `97_rule_evidence.md` `RPT-015`）

> 「**先跑返水奖金，再跑 VIP 升降级**，即按升降级**前**的等级计算返水」
> 出处：`doc:杏彩报表v1.00 §盈亏汇总·返水`

**C · 冲突在哪 ＋ 什么场景会炸**

**顺序整个反过来。** 会炸的场景：会员昨天从 VIP 3 升到 VIP 5。
照档案（先返水后升级）＝ 按 VIP 3 的返水比例发；照现况（先升级后返水）＝ 按 VIP 5 发。
**同一个人、同一天、两个金额。** 而且返水是每天跑，错一天就错一批。

🔴 **但这条不是重点，重点是它暴露的面**：

`98_rule_governance` §97 定义 `doc:<档名>` ＝ **外部参考文档**。
`杏彩报表v1.00` 是**别家平台的**，全库有 **7 条 `RPT` 条款**拿它当唯一依据：
`RPT-003` `RPT-004` `RPT-008` `RPT-009` `RPT-011` `RPT-012` `RPT-015`。

Luke 2026-08-21 逐字：

> **大部份是从这个平台移植过来，但有些为了业务需求，有调整过，所以要另记录**

⇒ **这 7 条里有几条已经被调整过、档案没跟上，目前不知道。** `RPT-015` 是第一个被抓到的。

**✅ 处置（Luke 2026-08-21 裁定）**

> 本地盘的这个依照我今天说的来，你注明一下

1. `RPT-015` **已改**为本平台口径，两个档都注明「原文是移植来源、方向相反」。
2. 🔴 **立一条通则**（已写进 `02_prd_spec_report §4` 第 14 项）：
   **凡是只有 `doc:杏彩报表v1.00` 单一出处的条款，一律视为「移植来源」而非「本平台现况」，落地前要向 Luke 复核。**
3. ⬜ **待办：其余 6 条逐条复核。** 不急，碰到哪条查哪条。

**旁证**：`proto:Team Turnover Bonus_团队流水活动` 原型自己就写着
「活动排序：若不输入，**依照目前杏彩体育的排序规则**」——移植关系在原型上留有痕迹。

---

## `C-011` · `GGR Margin` 的合计行不是 `--`，是重算 ✅ 2026-08-21 已裁

**A · 线上现况写什么**（`shot:PlatformReport` 现实后台，`PRE`，2026-08-21 Luke 提供）

合计行 `GGR Margin ＝ 5.95%`，而 `Company GGR 58,660.53 ／ Bet Amount 985,257.54 ＝ 5.95%`。
⇒ **用合计后的分子除以合计后的分母，重新算一次。**

**B · 档案写什么**（`90_field_dictionary` §1 `GGR Margin` 备注，v0.5）

> 🔴 **比率字段不参与合计行加总，合计填 `--`**（`RPT-012`）——`--` 只出现在合计行，数据行永远给数字

**C · 冲突在哪 ＋ 什么场景会炸**

「不加总」是对的，「填 `--`」是错的。**两件事被写成了一件。**
会炸的场景：开发照字典做，合计行的 `GGR Margin` 渲染成 `--`，与现实后台不一致；
运营看不到整体毛利率，得自己拿计算机除。

🔴 **这条是怎么写错的**：v0.5 那句是照 `RPT-012` 的字面「百分比类标 `--`」**推**出来的，**当时没有实证**。
现在有截图了。⇒ **`RPT-012` 的「百分比类标 `--`」要连带重核。**

**✅ 处置（Luke 2026-08-21）**

> 那就比照重算，**有的字段处理方式不同，这个正常**

字典 `GGR Margin` 备注已改为「④ 合计行 ＝ 重算，不是加总，也不是 `--`」，并注明更正了 v0.5 那句。
⬜ `RPT-012` 条文本身尚未改 —— 它管的是全库所有比率字段，**动它要先量一遍全库有几个比率字段、各自怎么处理**，不在本轮。

---

## `C-012` · 两份现行 PRD 对「多笔奖金怎么排序」用了不同的时间字段 ✅ 2026-08-21 已结

**A · `prd:PRD_v2.9_bonusUsageRestriction.md`（现行版，2026-08-14）写什么**

它是「活动奖金使用限制」的**主 PRD**，多笔奖金 FIFO 这套机制就定义在这里。逐字：

> `G5` **多笔奖金按领取入账先后依次分配**（同时刻按奖金记录 ID 升序），同一份有效投注不重复计入多笔

> §4.4 第 2 条：**排序键** ＝ `领取入账时间 ASC, 奖金记录 ID ASC`

全档 20 余处一律用「**领取入账**」，L0 术语表并写死：
「**派发** ＝ 奖金派给用户、出现领取按钮但**钱还没进账**；**领取入账** ＝ 用户手动领取、钱进可用余额」。

**B · `prd:PRD_v1.7_FirstDepositGift.md`（现行版，2026-08-13）写什么**

§297：

> **多笔并存的分配顺序** ｜ 按**发放时间 FIFO** 分配

`AC31`：

> 同一笔有效投注，用户同时持有两笔奖金 → 只推进一笔（按**发放时间** FIFO），不重复计入（`G5`）

**C · 冲突在哪 ＋ 什么场景会炸**

**同一套机制、两个不同的时间字段。** 而依 `00_domain_baseline` `D-40`，
「发放」与「领取入账」是两个时刻，**手动领取的活动可能差好几天**。

会炸的场景：用户手上两笔奖金 —— A 先发放（`8/18`）但 `8/22` 才领；B 后发放（`8/20`）当天就领。

| 照哪一份 | 排序 |
|---|---|
| `bonusUsageRestriction`（按领取入账）| **B 在前**（`8/20` 领）、A 在后（`8/22` 领）|
| `FirstDepositGift`（按发放）| **A 在前**（`8/18` 发）、B 在后（`8/20` 发）|

⇒ **同一笔有效投注推进的是不同的那一笔奖金**，两笔的「已完成流水」互换，
最后谁先解锁、谁先能提款**完全相反**。

🔴 **而且 `FirstDepositGift` 的这套机制本来就是复用 `bonusUsageRestriction` 的**——
它不该自己定一套排序键。

**🔴 这条是怎么冒出来的**

不是特地去找的。2026-08-21 为了核 `02_prd_spec_report §3.2` 的「发放时间」错在哪，
`grep` 全库 41 份 PRD 的「发放时间」，14 行里落出这两处。

⚠️ **两份源档（`PRD_v1.5_FirstDepositGift` / `PRD_v2.8_bonusUsageRestriction`）也写「发放时间」，
但那是源档，不列入本条**——本条只管现行交付物。

**✅ 处置（Luke 2026-08-21 裁定，选 ㈠）**

问「`type=65 首存送礼活动` 是手动领取还是自动领取」，Luke 答：**手动**。
⇒ 发放与领取是两个时刻，两份档的排序键**确实会排出不同结果**，不是等价写法。
⇒ 也印证了 `D-41` 那份自动领取清单（发薪日 ＋ VIP 三礼金）是全的，**首存不在里面**。

**已做**：`PRD_v1.7_FirstDepositGift.md` → **`PRD_v1.8_FirstDepositGift.md`**（2026-08-21）

- `G5` 由「先发的先算完」改为「**先领到手的先算完**」。
- 「多笔并存的分配顺序」由「按**发放时间** FIFO」改为「按**领取入账时间** FIFO（同时刻按奖金记录 ID 升序）」，
  并写明**不是按发放时间**、本活动是手动领取。
- `AC31` 改写成**真正能验出差异的场景**：两笔奖金的**发放先后与领取先后相反**（A 先发放后领、B 后发放先领）⇒ 推进 B。
  🔴 **原来的 `AC31` 验不出这个 bug**——它只写「同时持有两笔奖金」，没规定两笔的先后关系，
  照发放排与照领取排会得到同一个答案，测试跑绿也说明不了什么。
- `lint_prd` **0 失败 0 告警**；引用面 6 份档共 9 处已按既有规则处理
  （指路的改新名；`HANDOFF` 与 `96_spec_findings` 记「当时量到什么」的**显示文字保留旧名、只改 href**）。

**🔴 本条留下的判据**

> **一份 PRD 复用另一份的机制时，被复用那侧的关键字段名要逐字对齐，不能各写各的。**
> 这次两边都写了「FIFO」，看起来一致——**差异藏在排序键的那个时间字段上**，
> 不逐字比对根本看不出来。

⚠️ 全库还有几处这类「复用了但字段名没对齐」，**本轮没有量**。碰到再查。

---

## `C-013` · 注册送礼活动 `更新2` 的「文档链接」指向的是首存活动的 PRD ✅ 2026-08-22 已结 —— **不是冲突，是原型施工中**

**A · 原型写什么**

`proto:更新2_Registration Bonus_注册送礼活动`（2026-08-22 实抓）页面右上角只有一个说明框，逐字：

> HackMD 文档链接：https://hackmd.io/@lukedoc/BkrRttBrGe
>
> 客户端 html 示意下载：https://drive.google.com/file/d/1oeZRoRe19b4nfr0mqK4guCR2a2By_WoG/view?usp=drive_link

站上版本记录 `v1.149 · 2026.08.22` 逐字：

> 1. Back Office_后台＞活动管理＞活动模版＞ 更新2_Registration Bonus_注册送礼活动 ：迭代首存活动。

🔴 **整页没有任何编号标注**。`更新1` 有 14 个标注编号，`更新2` 一个都没有——
说明这一版把「文字规格」整块外移到了那两条链接。

**B · 档案写什么**

[`02_BO_需求分类.md`](../站点盘点/02_BO_需求分类.md) 把 `BkrRttBrGe` 挂在需求单元 **1「First Deposit Bonus_首存活动」**。

2026-08-22 重抓该文档（`curl .../download`，200 / 80,875 B），与库内 `_raw/hackmd/BkrRttBrGe.md`
**逐行 diff ＝ 0**。它的标题是「活动模板 · 首存送礼活动（First Deposit Bonus）· PRD」，v1.4 / 2026-07-28。
全文**没有一句**讲注册送礼活动。

**C · 冲突在哪 ＋ 什么场景会炸**

开发照「文档链接」点进去会拿到**另一个活动**的 PRD。两边的派奖策略结构不一样：

| | 首存 PRD 有 | 注册送礼原型有 |
|---|---|---|
| 派奖 | 单笔充值金额档位表 ／ 奖金类型（固定金额 vs 按比例）／ 上限值 ／ 流水倍数计算规则 | 指标（注册账号）／ 对应彩金 ／ 流水倍数 |
| 时间 | 无「注册起止时间」 | **有**「注册起止时间」 |

⇒ 照它做会做成首存。

**✅ 处置（Luke 2026-08-22 裁定）**

逐字：

> 这个文档链接先忽略，还没写完，我只是从首存活动那边复制过来的页面，然后改成注册，等之后文档写完，我会更新这个文档链接

⇒ **不是两边打架，是链接还没换。** 本条结案，不必回原型。

🔴 **但它留下一条判据，比这条冲突本身值钱**：

> **一页原型是从另一个活动复制来改的时候，页上每个元素都要问一次「有意沿用，还是复制残留」。**

本次实测到的证据：`更新2` 与 `更新1_First Deposit Bonus_首存活动` 逐项文字比对，
**版面、章节切法、说明框、场馆勾选区、连那两条外链，全部一模一样**。
差异只有注册送礼自己那几个字段。⇒ 拿不准的一律问，不要从「首存那份怎么写」直接推。

---

## `C-014` · 规格档说六个活动有「KYC 同人互斥」，现行原型都已拿掉 ✅ 2026-08-22 已裁

**A · 原型写什么**

2026-08-22 抓 10 页活动模板原型逐页比对该字段：

| 页 | `*KYC 同人互斥：` |
|---|:-:|
| 注册送礼（母版）／ 首存（母版）／ 每日抽奖（母版）| **有** |
| **注册送礼 `更新1`／`更新2`** | **无** |
| **首存 `更新1`** | **无** |
| **每日抽奖 `更新1`** | **无** |
| 累计充值 ／ 累计流水 | **有**（两者都还没有「更新 N」版）|
| 邀请好友 | **有**，另有 `*被邀请人 KYC 同人互斥：`（也还没有「更新 N」版）|

⇒ **规律不是「有些活动有、有些没有」，是「迭代过的都拿掉了」。**

**B · 档案写什么**

[`../PRD_Spec/04_prd_spec_campaign.md`](../PRD_Spec/04_prd_spec_campaign.md) §1.2「以下四个字段母版没有，用到时才写」那张表，逐字：

> | **KYC 同人互斥** | 首存 / 注册送 / 累充 / 累计流水 / 每日抽奖 / 邀请好友 | 与「自我互斥」「禁止同 IP」并列的**第三道防重**；邀请好友另有独立的「被邀请人 KYC 同人互斥」——**两个字段，不是一个** |

**C · 冲突在哪 ＋ 什么场景会炸**

规格档把**首存**与**注册送**列为「用得到」，而这两个活动的现行原型都已经拿掉。
照 §1.2 写 PRD，会替后台补一个**根本不存在的字段**，开发照着做就多做一个功能。

⚠️ 这条不是新长出来的——`PRD_v1.4_FirstDepositGift` v1.0 版本记录（2026-07-27）就逐字写过
「M1 精简：删除「KYC 同人互斥」」，`PRD_v2.4_newYearWheel` §6.1.4 也写了
「**KYC 同人互斥**删除（KYC 审核时已做同人核验）」。**⇒ 规格档落后交付物将近一个月。**

**✅ 处置（Luke 2026-08-22 裁定）**

逐字：

> 这个已经拿掉了，先前是打算要去做同人互斥，但是开发说这个太吃效能，所以后面就不做了，直接让运营从源头作，如果同人给过，那活动也让参与。也就是说，如果运营认为同人不给过 KYC，则直接就不能参加活动，这样就可以了

🔴 **这道防重没有消失，是换了位置**——由活动侧移到 KYC 审核那一关。活动侧不再有对应字段。

**已做**（2026-08-22）：

- [`../PRD_Spec/95_luke_rulings.md`](../PRD_Spec/95_luke_rulings.md) 登记 `R-028`（逐字 ＋ ✅ 已确认），27 → 28 条。
- [`../PRD_Spec/04_prd_spec_campaign.md`](../PRD_Spec/04_prd_spec_campaign.md) v0.7 → **v0.8**：§1.2 那张表由四个字段收为三个，
  废止理由与上面那张实测表改写在表下；§1.1 实测模块序列表补 `更新2` 一行。条款数不变（32 条）。
- 既有交付物**不回头改**（`98 §6.5` 规格改动不追溯已交付的 PRD）。
  两份早已自行删掉此字段的 PRD，写的理由与本裁定一致，不必动。

**🔴 本条留下的判据**

> **规格档里「哪些活动有这个字段」这类清单，要标是哪一版原型量的。**
> 这条清单当初量的是母版页，母版页至今没改过、所以它「没错」——
> 错在**它量的那一版已经不是现行版**，而清单本身看不出这件事。

---

## `C-015` · 原型说「团队人数含自己」，Luke 核实后是**不含** ✅ 2026-08-22 已裁

**A · 原型写什么**

[`../站点盘点/02_BO_需求分类.md`](../站点盘点/02_BO_需求分类.md) §四 61 那一页（`proto:更新1_累计活跃会员`），
`团队注册人数 / Team Registrations` 的说明逐字两句：

> 「1. 统计时需要包含自己及以下的团队。」
> 「2. 团队的账号属性包含代理+会员+**自己**。」

同一页的 `直属注册人数 / Direct Registrations` 则写：

> 「2. 团队的账号属性包含代理+会员。」「3. 注意：**不包含自己**。」

⇒ **原型把两者写成一含一不含**，而且是 `1/19 更新需求` 那一批特地补上去的。

**B · 实况是什么**

Luke 2026-08-22 逐条核实后裁定（`ruling:R-047` `R-048`）：

| 字段 | 原型说 | 🔴 实况 |
|---|:-:|:-:|
| `代理盈亏` 的 `注册人数` | **没写** | **不含自己** |
| `团队注册人数` | **含自己** | 🔴 **不含自己** |
| `直属注册人数` | 不含自己 | 不含自己（一致）|

**C · 冲突在哪 ＋ 什么场景会炸**

**三个「注册人数」实际上口径一致（都不含自己），原型却把 `团队` 那个写成含自己。**

照原型写进 PRD，开发会给 `团队注册人数` 多算一个人（该代理本人）。
🔴 **一层代理差 1、整条线逐层累加**——代理树越深，`团队注册人数` 与 `直属注册人数` 的差距越离谱，
而这两个数**就是里程碑奖金与持续发展奖金的派奖基数**（`proto:里程碑奖金` / `proto:持续发展奖金`）。
⇒ **会直接影响派给代理的钱。**

**处置**：以 Luke 核实值为准，原型那句**不改**（`_raw/` 留原样，见 [`HOWTO.md`](HOWTO.md) §六 第 7 条），
在字段总表的定义栏写死「不含自己」并标本条编号。
⚠️ **这一条也是「原型正文不等于线上实况」的第 N 个实证**——原型说明写得越具体，越要回头核。

---

## `C-016` · `活动派奖记录` 线上 18 栏，原型文档说「当前 13 栏、那几栏已移除」 ✅ 2026-08-26 已裁

**A · 线上截图写什么**

`shot:活动派奖记录/u2.png`（**2026-08-19 拍，`PRE` 环境**）——我打开原图逐栏看过，**表头 18 栏**，
其中这 4 栏**清清楚楚在**（中英并列，且有数据）：

| 栏 | 英文 | 截图上的值长什么样 |
|---|---|---|
| `已完成解锁流水` | `Completed Turnover` | `0.0000` ／ `350.0000` ／ `105.0000` |
| `是否满足出款` | （无英文名）| `是/Yes` ／ `否/NO` |
| `流水限制场馆` | `Turnover Whitelist` | `SLOT(JILI,PG,FC,EVO,J...` |
| `操作` | `Operation` | `自动出款通过/Verified` ／ `奖金未发放/Not Credited` ／ 🔵 `流水人工审核通过/Turnover Verified`（**蓝字带下划线，可点**）|

🔴 **`操作` 那一栏是真的按钮**：截图里正开着一个确认框，逐字
「**确定要出款流水通过吗，通过后提款不在拦截这一单奖金出款流水**」。

**B · 原型文档写什么**

`proto:活动派奖记录`（该页内嵌一份 v1.0 / 2026-06-13 的栏位定义文档）：

> 「以导出的实际列表结构（**13** 栏）为准。历史版本中存在、**现已移除的栏位**见附录」

附录「历史已移除栏位（仅供追溯）」逐字点名了其中三栏：

> 「**出款流水、已完成解锁流水**：已并入阶段流水计算，不再单独展示」
> 「便利贴中曾标注『暂留或之后会用到』的栏位（完成次数、**流水限制场馆**、发放状态需审核、下级用户），
> 经确认当前 13 列结构中**已不包含，视为已移除**」

`是否满足出款` 另见同页早期便利贴逐字：「**出款状态、是否满足出款：跟发放意思是一样的**」。

⚠️ **该文档自己还内部矛盾**：正文说「13 栏」，但它下面那张「栏位总览」表**列了 14 行**（`1`~`14`）。

**C · 冲突在哪 ＋ 什么场景会炸**

**字典要不要收那 4 条，两边给的答案相反。**

| 照谁写 | 后果 |
|---|---|
| 照原型文档（不收）| 🔴 **线上真的有这 4 栏，而字典里查不到。** 下一代要动 `流水限制场馆` 时，
本知识库**答「没有这个字段」**——正是 Luke 立这个需求要挡的事（「加字段前的必经关口」）|
| 照线上截图（收）| 可能收进 4 个**已排期移除**的栏，字典多 4 条死条目 |

🔴 **本轮的处置：照线上截图收，但每一条都标明原型文档说它已移除。**
判据是 `ruling:R-046` 的反面——那次 Luke 裁定「线上没有的不收」，
⇒ **「线上有的就该收」是同一条判据的另一半**，且截图（2026-08-19）比原型文档（2026-06-13）新两个月。

**✅ 2026-08-26 已裁**（`ruling:R-059`）。Luke 逐字：

> 「**那四欄是現在正在作業中的，還沒上線，正在 pre 環境測試中，要寫**」

⇒ **照线上截图收满，四条全写进字典。**

🔴 **但结论对、我的理由错了一半，要更正。**

我原本推的是「截图（2026-08-19）比文档（2026-06-13）新两个月 ⇒ 以截图为准」。
**方向对，因果错**——那 4 栏**不是「文档过期、线上早就有」，是「正在做、还没上线」**。
⇒ 文档写在这批工作之前，**它当时是对的**；对的是「它没写到后来才开工的东西」。

🔴 **连带更正一条既有判准**（`_kb/HOWTO.md` §六 第 6 条）：

| | 原本写的 | 🔴 本条实证之后 |
|---|---|---|
| `PRE` 截图的**结构** | **可信** | **不一定等于线上现况**——`PRE` 独有的栏可能是**还没上线的在建功能** |
| `PRE` 截图的**值** | 只代表 `PRE` | 不变 |

⇒ **碰到 `PRE` 上有、生产没有的栏，判法是问「这是在做的，还是已经砍掉的」**，
不是直接当成「线上有」或「线上没有」。**这两种情况的处置刚好相反**
（在做的 ⇒ 要写；砍掉的 ⇒ 不写，`ruling:R-046` ／ `R-058`）。

---

## `C-017` · ~~`phstore_show_id` 配了一个实体站管理里查无此站的 ID~~ ✅ 已结 —— **不成立，是我判错了**

### A · 线上写什么

**`网站管理 ＞ 基本配置 ＞ 运营参数`**，`Id 230003` `phstore_show_id`（注册可选实体站列表），
📛 **PRE 值**（Luke 2026-08-28 补拍，见 [`enums/base_config_items.md`](enums/base_config_items.md) §3.4）：

| 栏 | 值 |
|---|---|
| 品牌栏 ①（不继承）| `1,2,3,30002,4,5,6` |
| 品牌栏 ②（不继承）| `1,2,3,30002` |

同一环境的 **`运营管理 ＞ 实体站管理`**（`shot:实体站管理/u0`，后端模板 `phstore_list.html`）
**只有 ID `1`~`10`**，一条 `30002` 都没有。

### B · 档案写什么

`doc:hackmd/S1js4UUWGl` §5.2 第 1 点，逐字：

> **解析与排序**：读取 `phstore_show_id` 配置中的 ID 集合字符串（如 `2,3,1`），严格按照该字符串分割后的数组先后顺序，去匹配内部硬编码字典。

**「匹配不到怎么办」一个字都没写。** 同档 §5.3 只写了一种空态：

> **空状态处理**：若后端返回的 `phstorelist` 为空，按系统通用 UI 规范隐藏实体站选择组件或进行阻断提示。

`prd:PRD_v1.3_phStoreMgmt.md` §5.2 则写明**本模块刻意不反查**，逐字：

> **禁用一个正被某平台配着的实体站，本模块不拦、也不提醒**——本模块**不反查**任何平台的配置。

### C · 冲突在哪 ＋ 什么场景会炸

**没有任何一份档规定「配置里的 ID 在字典里找不到时该怎么办」**，
而 `PRD_v1.3` §5.2 又刻意让这种情况**能够发生且无提示**——两边合起来是一个开口。

三种做法都说得通，做法不同结果差很远：

| 做法 | 结果 |
|---|---|
| 静默跳过 | 运营以为配了 7 个，前端只出 6 个，**没有人会发现** |
| 整条配置解析失败 | 一个字打错，注册页**整个下拉框空掉** |
| 回传一个空名称的项 | 前端渲染出一行空白，玩家选得到但绑不上 |

🔴 **两栏都含 `30002`，不是单一栏的手误。** 它可能是别的环境的站号、也可能是测试用的假号——
**判不出来，要问**。

⚠️ **值只代表 `PRE`**。要确认的是**规则**（解析不到怎么办），不是这一笔值本身。

**触发源**：需求 `27.注册可选实体站展示`（2026-08-28）。

### ✅ 2026-08-28 当日结（`ruling:R-092`）

Luke 逐字：

> 「**C-017 照你建议做**」

**采纳的建议原文**：静默跳过 ＋ 后台保存时就校验。**两条都要做，缺一条不成立**：

| # | 做什么 | 挡的是什么 |
|:-:|---|---|
| ① | **后台保存 `注册可选实体站列表` 时校验**，查不到的 ID 不给存、并指出是哪一个 | 新填进去的 |
| ② | **后端解析时静默跳过查不到的 ID**，其余照常下发；不因一个坏 ID 让整条配置解析失败 | 已经存进去的 |

🔴 **为什么只做 ① 不够**：实体站**不做删除**（`prd:PRD_v1.3_phStoreMgmt.md` L0 ④），
坏 ID 不会自己消失；现行配置里**已经有** `30002`，只加保存校验清不掉它。

⇒ 落点：`进行中/27.注册可选实体站展示/需求原文.md` §二.6。

### 🔴 2026-08-28 再更正：**本条不成立，是我判错了**

**新证据**（Luke 2026-08-28 的 F12 网络面板截图，注册页 `settings` 接口的 `Preview`）：

```
phstorelist: [
  {id: 1,     name: "BIG A Quezon City",              status: 1},
  {id: 2,     name: "BASILLADE STA. ANA",             status: 1},
  {id: 3,     name: "BASILLADE HOLIDAY PLAZA ARNAIZ", status: 1},
  {id: 30002, name: "uhiguymapces",                   status: 0}
]
```

🔴 **`30002` 解析得出名字** ⇒ **它是一个存在的实体站，只是禁用中**，不是「查无此站」。
本条 A 段整段站不住，`ruling:R-092` 处置的**触发实例**也随之作废。

**我为什么判错**：我拿 `shot:实体站管理/u0` 那一张列表当**全集**。
那张只列到 ID `1`~`10`，而该列表**排序是实体站 ID 由大到小**（`prd:PRD_v1.3_phStoreMgmt.md` §2.1）
⇒ `30002` 若与它同一份清单，**应该排在最上面**，截图上却没有。
⇒ 两者不是同一份清单：不是环境不同，就是那张截图有筛选、或分页没翻。**两种我都没去验。**

📌 **教训**：**「一张列表截图上没有」不等于「系统里没有」。**
判「查无此项」要看**解析结果**（接口回传解不解得出名字），不能看一张列表截图；
尤其那张截图的**排序规则**会决定该项该出现在哪里——**排序规则就在手边，我没拿来验。**

**处置**：✅ **已结——不是冲突。** 不必改任何档。
🔴 **但 `ruling:R-092` 那两条防呆仍然成立**（后台保存时校验 ＋ 后端解析时静默跳过）——
Luke 已裁定要做，只是**本轮举不出实例**，理由要改写成「防呆」而非「已有坏数据」。

⚠️ **更正过程中浮出两条真的**，见 `C-018` 与 `C-019`。

---

## `C-018` · ~~迭代上线那一刻，一个叫 `uhiguymapces` 的禁用站会直接显示给玩家~~ ✅ 已结 —— **不成立，那是 `PRE` 的测试数据**

**A · 线上写什么**

注册页 `settings` 接口回传的 `phstorelist` 第 4 项（同上）：

```
{id: 30002, name: "uhiguymapces", status: 0}
```

**前端现在把它过滤掉了**——同一张截图里，注册页下拉展开只有 3 项，没有它。

**B · 本次需求要什么**

`case:27` 要求**不再过滤**：配置里有的都显示，禁用的置灰、不可点（`ruling:R-089`）。

**C · 冲突在哪 ＋ 什么场景会炸**

🔴 **迭代上线的那一刻，`uhiguymapces` 这个名字会出现在玩家的注册页下拉里。**

它不像正式店名（其余三个都是 `BIG A Quezon City` 这类真实门店名）。两种可能，处置相反：

| 它是什么 | 该怎么办 |
|---|---|
| **测试建的** | 上线前**从 `phstore_show_id` 配置里移除**。留着就是给玩家看一串乱码 |
| **真的站、只是名字还没定** | 🔴 **改不了名。** `prd:PRD_v1.3_phStoreMgmt.md` `G1` 写明**名称建了就不能改**，全页没有任何改名入口 ⇒ 只能**新建一个名称正确的 ＋ 禁用这一个**，再改配置 |

⚠️ **这不是「本需求的规格问题」，是「本需求会让一笔既有数据曝光」。**
本档不做处置建议以外的事，但**上线前必须有人处理它**，否则玩家第一眼就看得到。

⚠️ **值只代表这张截图所属的环境**（`phstore_show_id` 回传 `1,2,3,30002`，与 `enums/base_config_items.md` §3.4
记的 **`PRE` 品牌栏 ②** 完全一致 ⇒ **这张 F12 很可能是 `PRE`，不是生产**）。
🔴 **生产上是不是也配了 `30002`，要另外核。**

---

## `C-019` · 注册页实体站下拉：档案说「置灰」，线上是「过滤掉」 📌 挂账

**A · 线上写什么**

Luke 2026-08-28 逐字：

> 「**目前是基本配置里的都会显示出来并且都可以点击，如果是在实体站管理禁用，但是又给配置到基本配置，那就会被前端过滤掉，不显示到下拉选单**」
> 「**简单一句话就是，现在只要在客户端显示出来的，都可以点击**」

**截图印证**：接口回传 4 项（3 项 `status: 1` ＋ 1 项 `status: 0`），
注册页下拉展开**只有 3 项，且没有任何一项是置灰的**。

**B · 档案写什么**

`doc:hackmd/rJDiZMtfzl`（`PRD_LoginPage_Carousel_v1.0`）§7「注册登录页 — 基础元素」，逐字：

> | 实体站下拉 | 下拉选单 | **接口读取** | Enum | 必填 | 第一项 | 共 5 项，仅第一项可选，其余置灰；绑定后不可编辑 |

**C · 冲突在哪 ＋ 什么场景会炸**

**两边讲的是同一个下拉，行为完全不同**：

| | 显示几项 | 禁用的怎么处理 | 哪些可点 |
|---|---|---|---|
| **档案** | 固定 5 项 | **置灰留着** | 只有第一项 |
| **线上** | 依配置，滤掉禁用的 | **整项不显示** | **显示出来的全部** |

🔴 **差别正好就是本需求要做的那件事。**
照档案读，会得出「置灰已经有了，本次只要把判据从『第几项』换成『status』」——
照线上读才知道「**置灰这个呈现方式本身就是新的**」。

**会炸的场景**：估工作量时漏掉置灰的样式定义（灰阶、游标、点击是否有回馈、无障碍属性），
以为是既有元件直接复用。

⚠️ **档案那一行不是写错。** `axure:更新4_regis_login_注册登录配置化` 的下拉确实是
「1 个真名 ＋ 4 个 `Gaming venue N is coming…`」——**档案照原型写，原型没跟上线上。**
⇒ 要更正的是**档案与原型两边**，不是只改一边。

📌 **教训**：**同一份档里，「本版新增」那几节是新的，「基线沿用」那几节可能是抄原型抄来的。**
`rJDiZMtfzl` 的 Part Ⅱ / Part Ⅲ 开头都写着「**已上线基线，本版一字未改**」——
**那句话保证的是「本版没动它」，不保证「它跟线上一致」。**

### ✅ 2026-08-28 当日结（`ruling:R-099`）—— **不成立**

Luke 逐字：

> 「**是测试建的**」
> 「**我给你看的是 PRE 环境，所以没有关系，目前有的 10 个已经全部建好，并且不支持编辑，如果未来还有新的，那就再新建就好**」

⇒ **那张 F12 是 `PRE`。** `uhiguymapces`（`id 30002`）是 `PRE` 上测试建的一笔，
**`PROD` 没有这个站** ⇒ 迭代上线不会把它曝光给玩家。**本条不成立，不必改任何档。**

🔴 **`C-017` 与本条是同一个根因造出来的两条假冲突**：**我把两个环境的数据当成同一个**。
F12 截图与基本配置截图**都是 `PRE`**，而 Luke 讲的可绑定名单 `1`/`3`/`6` 是 **`PROD`**。
我拿 `PRE` 的 `phstorelist` 去验 `PROD` 的名单，于是：

| 我造出来的 | 实际 |
|---|---|
| `C-017`「配了一个查无此站的 ID」 | `30002` 在 `PRE` 存在，只是禁用 |
| `C-018`「上线会曝光乱码店名给玩家」 | `PROD` 根本没有这个站 |
| `R-094` 的 ⚠️「`2` 未过审却启用，是合规曝险」 | 那是 `PRE` 的 `status`，`PROD` 另一回事 |

📌 **教训（已写进 `ruling:R-099`）**：
**同一轮拿到多张截图时，先逐张问「这是哪个环境」，再开始交叉比对。**
🔴 **本库早写着「值只代表 `PRE`」**（`HOWTO §六` 第 6 条 ／ `C-002`）——
**我知道这条，但只对「后台截图」套用了它，没对「前端接口回传」套用。**
⇒ **判准要扩**：`PRE` 这个限定管的是**该环境产出的一切**，包含接口回传、日志、导出档，不只是截图。

---

## `C-020` · 注册页两个 placeholder：档案写的字与线上不一样 📌 挂账

**A · 线上写什么**

Luke 2026-08-28 补的注册页截图（同一批 F12 的左侧手机画面），两个输入框的 placeholder 逐字：

| 栏位 | 线上 |
|---|---|
| 手机号 | `Mobile Number (09*********)` |
| OTP | `Enter your OTP` |

**B · 档案写什么**

`doc:hackmd/rJDiZMtfzl`（`PRD_LoginPage_Carousel_v1.0`）§7 表格下方，逐字：

> **placeholder 与样式**：手机号 `Phone Number (09*********)`、OTP `Verification code`；输入时隐藏 placeholder。

**C · 冲突在哪 ＋ 什么场景会炸**

**两个都对不上，而且是逐字级的差别**：

| | 档案 | 线上 |
|---|---|---|
| 手机号 | **Phone** Number (09*********) | **Mobile** Number (09*********) |
| OTP | Verification code | Enter your OTP |

🔴 **placeholder 是玩家看得到的字，属文案。** 而 `HTML_Spec/01` 的 `HTML-005` 要求
「原型的 placeholder 要在配对 PRD ／ Axure 里找得到出处」——照档案抄就会**把线上没有的字画进原型**，
下一个人再拿原型当基线，错的字就固化下来。

⚠️ **和 `C-019` 是同一族**：`rJDiZMtfzl` 的 Part Ⅲ 开头写着「已上线基线，本版一字未改」，
**那句话保证的是「本版没动它」，不保证「它跟线上一致」**。这已经是同一份档的第二处。

**处置（`case:27` 的原型先这样做）**：原型照**线上**那两句写。

🔴 **只要改档案一处，Axure 不必动**（2026-08-28 实测更正）：
`_raw/bo/049b_更新4_regis_login_注册登录配置化.json` 的 `visible` ／ `hidden` ／ `notes` 三处
**都搜不到 `Phone Number` ／ `Verification code` ／ `Enter your OTP`** —— 原型上只有 label `Mobile Number`，
**没有画 placeholder**。⇒ 这两句只存在于 HackMD 那一份档里。
⚠️ **本条原写「档案与 Axure 两边都要更正」，是我没查就照 `C-019` 的形状套过来的。**
`C-019`（下拉五项）确实两边都有，**本条只有一边**。

**触发源**：`case:27` 画客户端原型时逐字对照线上截图。

---

## 📌 `C-019` 与 `C-020` 的共同处置（2026-08-28 裁定：本轮不改）

Luke 逐字：

> 「**不用改动其他需求的档案**」
> 「**如果之后有需要更新或我要做到知识库和总入口的时候，再来调整就好**」

⇒ **两条都成立、也都查证到位，但这一轮不动 `doc:hackmd/rJDiZMtfzl`、也不动 Axure。**

### 要改的话，改哪几处（查证过的清单，回来时直接用）

| 条 | 档 | 位置 | 现在写的 | 要改成 |
|---|---|---|---|---|
| `C-020` | `doc:hackmd/rJDiZMtfzl` | Part Ⅲ §7 表格下方（本库副本第 **231** 行）| 手机号 `Phone Number (09*********)`、OTP `Verification code` | 手机号 `Mobile Number (09*********)`、OTP `Enter your OTP` |
| `C-019` | 同上 | Part Ⅲ §7 表格「实体站下拉」那一行（第 **222** 行）| 共 5 项，仅第一项可选，其余置灰 | 🔴 **建议不写规格、改成指向 `prd:PRD_v1.3_registrationPhStoreSelect.md`**（理由见下）|
| `C-019` | `axure:更新4_regis_login_注册登录配置化` | `Gaming Venue` 下拉的五个选项 | `BIG A Quezon City` ＋ 四个 `Gaming venue N is coming…` | 依线上实况。⚠️ **它是设计稿不是规格，不改也不误导开发** |

⚠️ **`C-020` 只要改档案一处**——Axure 上根本没有那两个 placeholder（三处 `grep` 全 0），详见该条。

🔴 **`C-019` 为什么建议「指过去」而不是「照线上写」**：
那一栏的规格**还会再变**（PAGCOR 逐站开放、配置一直调）。照现况写一次，下次上线又要再改一次。
⇒ **那一行不写规格、指向 `case:27` 的 PRD**，以后只改一处。

### 🔴 回来改的触发条件（三个，任一命中就回头处理）

| # | 触发 |
|:-:|---|
| 1 | **`doc:hackmd/rJDiZMtfzl` 本身要改版**（不论为了什么）——顺手把这三处一起改掉 |
| 2 | **`case:27` 真的上线之后**——那时线上行为变了，档案与现况的差距会再扩大一层 |
| 3 | **要把注册登录页的基线收进本知识库、或做进总入口时**（Luke 逐字点名的那两件）|

### 根因（本轮只记录，不处理）

`doc:hackmd/rJDiZMtfzl` 的档名是《**注册页新增轮播图显示** · PRD》——**它是轮播图那个需求的 PRD**，
Part Ⅱ / Part Ⅲ 是把注册登录的整份基线**抄进去当附录**，档里逐字写着：

> 注册登录与 KYC 流程为**已上线基线，本版未改动**，完整规格并入 Part Ⅱ / Part Ⅲ 供自包含查阅。

🔴 **问题在「抄一份」。** 那句话保证的是「**本版没动它**」，**不保证「它跟线上一致」**——
抄的那一刻是对的，之后线上改了，抄本不会跟着改。**两个月内已经漂了三处**（下拉行为 ＋ 两个 placeholder）。

⚠️ **要治这一层就是「把注册登录页基线独立成一份档、各需求指过去」**，会动到好几份既有 PRD。
**Luke 2026-08-28 裁定本轮不做**，真要做另开需求号。

---

## `C-021` · ~~`30002 uhiguymapces` 又出现在下拉里，而 `C-018` 已判它 `PROD` 没有~~ ✅ 当日已结 —— **不成立，那两张也是 `PRE`**

> **裁定**（`ruling:R-115`，Luke 2026-08-28 逐字）：「**这个忽略即可，我的截图是 PRE 环境的**」
>
> ⇒ 与 `C-018` **同一个理由、同一个结论**。`PROD` 那 10 个站里没有 `30002`。
>
> ⚠️ **同一个坑第二次，但这次没有踩下去。** `C-018` 那次是我**自己推断**两个环境的数据可以交叉比对，
> 凭空造出一条合规曝险和一条假冲突；这次照 `ruling:R-099` 的教训**只问了一句「这两张是哪个环境」**，
> 没有下判断、没有写进 PRD 的规则里。**代价是多问一句，收益是没有再造一条假的。**
>
> ⇒ 连带：`PRD_v1.0` 的 `OP-1` 结案，待确认项 **1 → 0**，该节整节删除（`PRD_v1.1`）。

**以下是开这条时写的原文，留着当记录。**


**触发源**：需求 `29.监理报表新增实体站筛选`。Luke 2026-08-28 传来两张**线上下拉展开**截图。

**A · 这一轮的截图写什么**

两张截图的 `GamingVenue` 下拉展开后，选项**一模一样**，都是 12 项：

```
All（其中一张写 All Gaming Venue）
1 - BIG A Quezon City
2 - BASILLADE STA. ANA
3 - BASILLADE HOLIDAY PLAZA ARNAIZ
4 - BASILLADE MALIBAY
5 - BASILLADE PEDRO GIL
6 - POWER UP ARNAIZ
7 - POWER UP ANGEL LINAO
8 - OLYMPUS GIL PUYAT
9 - OLYMPUS PANDACAN
10 - OLYMPUS SAN ANDRES
30002 - uhiguymapces
```

🔴 **其中第二张的页脚逐字写着 `SQL Info: Not available in production environment.`**

**B · 档案写什么**

[`../PRD_Spec/95_luke_rulings.md`](../PRD_Spec/95_luke_rulings.md) `R-099`，Luke 2026-08-28 逐字：

> 「**是测试建的**」
> 「**我给你看的是 PRE 环境，所以没有关系，目前有的 10 个已经全部建好，并且不支持编辑，如果未来还有新的，那就再新建就好**」

据此 `C-018`（`uhiguymapces` 会曝光给玩家）**当日判为不成立**——理由是那份证据来自 `PRE`，`PROD` 没有这一笔。

**C · 冲突在哪 ＋ 什么场景会炸**

**两件事对不上**：`R-099` 说 `PROD` 只有 10 个、`30002` 是 `PRE` 的测试数据；
这一轮的截图却在下拉里列出 `30002`，而其中一张的页脚自称 `production environment`。

⚠️ **本条刻意不下判断。** 三种可能都还开着：

| 可能 | 后果 |
|---|---|
| 这两张也是 `PRE` | `C-018` 维持不成立，本条当场结掉，`29` 不受影响 |
| 这两张是 `PROD`，`30002` 真的在生产 | 🔴 **`C-018` 要重开**；且 `29` 的下拉会列出一个测试站给审查单位看 |
| 页脚那句话不是环境指示 | 判据本身要更正 |

🔴 **不自行推断的理由就是 `R-099` 自己的教训**：
「**同一轮拿到多张截图，先逐张问「这是哪个环境」再交叉比对**」——
上一次没问，凭空造出一条合规曝险与一条假冲突（`C-018`），**两条都是假的**。

**要问 Luke 的只有一句**：**这两张截图是 `PRE` 还是 `PROD`？**

⚠️ **对需求 `29` 的影响面很小**：本需求只是加一个筛选项，**列什么由 `实体站管理` 的全量决定**，
不论 `30002` 在不在，`29` 的规则一个字都不用改。**要处理也是 `实体站管理` 那一侧的事。**

---

## `C-022` · 冻结状态的中文 5 个值，与 `Freeze Type` 的英文 5 个选项只对得上 4 个 ✅ 当日已结 —— **中文翻错了**

**发现于**：`case:30`（冻结解冻日志加手机号栏位）查连动时，Luke 2026-08-28 提供两张截图。

### A · 线上写什么

**甲｜`Frozen/UnFroze Log` 的 `冻结状态` 筛选下拉**（逐字，由上到下）：

`所有` ／ `完全冻结` ／ `可登录，不可投注，不可充提` ／ `不可投注，可充提` ／
`可登录和充值，不可投注和提款` ／ `仅冻结充值`

⇒ **`所有` 是全选、不是值**，实际值域 **5 个**。

**乙｜`Freeze_冻结` 页的 `Freeze Type` 单选**（逐字，含方括号里的号）：

`[1] Freeze completely` ／ `[2] Login allowed, no betting, no deposit, no withdraw` ／
`[3] Login allowed, no betting, deposit allowed, withdraw allowed` ／
`[5] Login allowed, betting allowed, no deposit, no withdraw` ／
`[7] Login allowed, betting allowed, no deposit, withdraw allowed`

⇒ 同样 **5 个**。

### B · 档案写什么

[`../PRD_Spec/90_field_dictionary.md`](../PRD_Spec/90_field_dictionary.md) 先前两行都写
「⚠️ 值域未取得 ⇒ §4 缺口」，**没有任何一份档写过这两组是不是同一套**。

### C · 冲突在哪 ＋ 什么场景会炸

**四个对得上**：

| 中文 | 英文 |
|---|---|
| `完全冻结` | `[1] Freeze completely` |
| `可登录，不可投注，不可充提` | `[2]` 登入✓ 投注✗ 充值✗ 提款✗ |
| `不可投注，可充提` | `[3]` 登入✓ 投注✗ 充值✓ 提款✓ |
| `仅冻结充值` | `[7]` 登入✓ 投注✓ 充值✗ 提款✓ |

🔴 **剩下这一对，四个维度里有两个刚好相反**：

| | 登入 | 投注 | 充值 | 提款 |
|---|:-:|:-:|:-:|:-:|
| 中文 `可登录和充值，不可投注和提款` | ✓ | ✗ | **✓** | ✗ |
| 英文 `[5] Login allowed, betting allowed, no deposit, no withdraw` | ✓ | **✓** | **✗** | ✗ |

**什么场景会炸**：有人写 PRD 或做原型时，把这两组当成同一套的中英对照，
**拿英文去替中文**（或反过来），运营选了「不可投注」实际却放行了投注、
选了「可充值」实际却挡掉了充值。**这两个维度都直接管钱。**

⚠️ **也可能不是冲突**：`[1][2][3][5][7]` 这个跳号很像**位元遮罩**（1、2、4 三个旗标的组合），
若真是遮罩，中文那五句可能是另一套人写的描述、与遮罩位对不齐。**没证据之前不推。**

### 处置

✅ **2026-08-28 当日开、当日结**（`ruling:R-138`）。**不是两套东西，是中文那一句翻错了。**

🔴 **Luke 亲自跑了一次线上，三件同时成立**：

| # | 实测到什么 | 出处 |
|:-:|---|---|
| 1 | 该账号最新一笔 `Freeze Type` ＝ `Login allowed, betting allowed, no deposit, no withdraw`（即 `[5]`）| `Unfreeze` 页（`user_unfreeze.html`）列表截图 |
| 2 | 同一时点**进得了游戏、下得了注** | 客户端截图：余额 `776.00`、`BET 1.00`、转轮可按 |
| 3 | 同一时点**充值被挡** | 客户端提示逐字 `User has been frozen for deposit and withdrawal` |

⇒ **英文对、中文错。`投注` 与 `充值` 两个词对调了。**

🔴 **更正**：`可登录和充值，不可投注和提款` → **`可登录和投注，不可充值和提款`**

⇒ 五个值全数对得上：

| 中文（更正后）| 英文 |
|---|---|
| `完全冻结` | `[1] Freeze completely` |
| `可登录，不可投注，不可充提` | `[2]` |
| `不可投注，可充提` | `[3]` |
| 🔴 **`可登录和投注，不可充值和提款`** | `[5]` |
| `仅冻结充值` | `[7]` |

⚠️ **先前那句「`[1][2][3][5][7]` 很像位元遮罩」的猜测，本条不采用也不反对**——
实测只证明了 `[5]` 那一条的语义，**跳号本身的成因仍未取得**，要用到再查。

### 连带

**改中文这件事已纳入需求 `30`**（Luke 逐字「顺便把这个中文改掉」）——
该需求 PRD 原写「本需求不改这一栏，只是把它写下来」，**该句作废**。

🔴 **本条属于「闸看不见」的一类**：中文与英文各自都通顺，两边都没有机器可判的错。
**只有把两页摆在一起看、再回线上实跑，才看得出来。**

---

## `C-023` · 6 条投注金额配置共用 2 个中文名 ✅ 已结 —— **中文名改 `_日`／`_周`／`_月` 后缀**

> 触发源：需求 `31.自我限制BetLimit新增周与月`（设计稿阶段抓到，非线上现况）

| 段 | 内容 |
|:-:|---|
| **A** | 原型 ①（暂缓设计稿）的 `Title` 栏：三条 `min_` 都叫「自我限制投注金额最小值」，三条 `max_` 都叫「自我限制投注金额最大值」 |
| **B** | [`_kb/enums/base_config_items.md`](enums/base_config_items.md) §一：基本配置第 2 层「没有分页器，一屏滚到底」，运营靠 `Title` 找配置 |
| **C** | **`Title` 栏分不出日／周／月**，只能靠 `Category` 英文键分辨。**炸在哪**：改错一条 ＝ 把月限当日限设。`Id` 还是倒序（`123454` 日、`123451` 周），排列顺序也不提示 |

✅ **2026-08-31 结**（Luke 逐字：「**你改成 _日、_周、_月，这样比较好，因为你现在的写法，他很难一眼看出来日周月……这样比较突显**」）：
六条中文名逐条以 `_日`／`_周`／`_月` 后缀收尾，日的两条同批改名（`PRD_v1.12` §6.1.3／§6.2）。

## `C-024` · `Daily Game Duration`（线上）vs `Daily Game Schedule`（原型＋知识库）✅ 已结 —— **用原型那套，线上要改**

> 触发源：需求 `31`。🔴 **这条是真的线上冲突，上线时线上要改名。**

| 段 | 内容 |
|:-:|---|
| **A** | **线上**（`shot:Self-Limitation/u1`，原图看的）：单选项与列表分组名都是 **`Daily Game Duration`**；达标筛选只有一个，叫 **`Reach 100%`** |
| **B** | **原型三页**都写 **`Daily Game Schedule`**；[`PRD_Spec/90_field_dictionary.md`](../PRD_Spec/90_field_dictionary.md) 与 [`_kb/fields/report_fields.tsv`](fields/report_fields.tsv) 收的全是 `Daily Game Schedule` |
| **C** | **同一栏两个名字，知识库收的是原型那个、线上是另一个。炸在哪**：PRD 写 `Daily Game Schedule`，开发在线上 `grep` 不到；写 `Daily Game Duration`，跟字典对不上 |

✅ **2026-08-31 结**（Luke 先逐字「**以线上为准，应该要配合调整为原型的文案**」，追问两种读法后答「**1**」）：
**最终名称用原型那套 `Daily Game Schedule`（后依 case:31 定案实作名为 `Gaming Schedule` 单选项），线上要改过来**，已进 `PRD_v1.12` §7.5.1；达标筛选同批由 `Reach 100%` 拆成 `Reach Limit` ＋ `Reach Warning`（§7.5.2）。知识库两处不改名（收的本来就是原型那套）。

## `C-025` · 客户端文案说「有延迟」，裁定说「0 时差」 ✅ 已结 —— **旧稿残留，删掉**

> 触发源：需求 `31`（设计稿内部矛盾）

| 段 | 内容 |
|:-:|---|
| **A** | 客户端原型 ③ `Bet Limit` 弹窗文案逐字：`1. Data: Usage is based on provider data and may have slight delays.` |
| **B** | Luke 2026-08-31 裁定 `N-10` 逐字：「**原本想用输赢额度，但这个取决于三方返回，可能会超过，导致被投诉，所以改成用投注额，投注是立马知道的，这样可以 0 时差**」 |
| **C** | **改用投注额的整个理由就是「0 时差」，那句文案讲的却是「有延迟」。炸在哪**：这句是给玩家看的免责声明，留着等于我方主动承认统计可能不准 ⇒ 反而给了投诉的理由 |

✅ **2026-08-31 结**（Luke 逐字：「**旧稿残留，删掉，这个提示语是什么场景下会生效？**」）：整条删除，剩余说明重新编号；出处落 `PRD_v1.12` §9.1.2（含被删句逐字原文）。

## `C-026` · 客户端月限 placeholder 与后台配置对不上 ✅ 已结 —— **一律读配置，示例值全作废**

> 触发源：需求 `31`（设计稿两页互相矛盾）

| 段 | 内容 |
|:-:|---|
| **A** | 客户端原型 ③ 三个输入框 placeholder 逐字：`Please enter 100-50,000` ／ `Please enter 500-100,000` ／ **`Please enter 5000-500,000`** |
| **B** | 后台原型 ① 配置值：日 `100`–`50000` ✅ ／ 周 `500`–`100000` ✅ ／ **月 `min` ＝ `1000`**，不是 `5000` |
| **C** | **月限最小值客户端写 `5000`、后台写 `1000`，差 5 倍。炸在哪**：客户端说明逐字写「**5. 填写范围依后台配置显示。**」——placeholder 本该读配置动态生成；两边示例值不一致，开发照哪边填都可能被当成规格 |

✅ **两轮结清**：2026-08-31 Luke 定「最小值三条统一 `100`、最大值日×10／×100」（逐字「**把数值做大点，让运营好配置**」）；
**2026-09-01 再改**（逐字「**日周月，默认都给 0，让测试和开发自己调整**」）⇒ **六条默认值一律 `0`（0 ＝ 该侧不设界），placeholder 一律读配置动态生成、不许硬编码**（`PRD_v1.12` §3.1.7／§6.1.4）。两边原型示例值全部作废。

---

## `C-027` · `Rekognize` 到底做几件事 ✅ 已结 —— **两支都叫，PRD 的状态机漏了一个触发源**

> 触发源：Luke 2026-09-01 逐字「**我记得 rekognize 这个按钮，会同时做两件事情，就是把脸上传，并且查找，你可以搜一下 AWS Rekognition 的官方文档看看**」

| 段 | 内容 |
|:-:|---|
| **A** | **Luke 的记忆（线上那一侧）**：`Rekognize` 按钮**同时做两件事**——把脸上传（入库）＋ 去库里查找。 |
| **B** | **档案写什么**：[`../待评审/04.KYC审查_AWS人脸辨识/Archive/PRD_v1.4_KYCFaceSimilarity.md`](../待评审/04.KYC审查_AWS人脸辨识/Archive/PRD_v1.4_KYCFaceSimilarity.md) `§4` 标题逐字「**`Rekognize`：重发查重**」，并写明「🔴 **本节是 `Rekognize` 的唯一出处**」；`§4.2` 状态表那一格逐字「**重新送查重请求**」。<br>同档 `§6.3` 入库状态机里，**入库只有一个触发源**：「（无）｜ KYC 提交，照片合格 ｜ 生成入库任务 ｜ 待入库」。<br>⇒ **PRD 里 `Rekognize` 碰不到入库。** |
| **C** | **冲突在哪 ＋ 什么场景会炸**：AWS 官方文档写明这是**两支不同的 API**，没有一支同时做——<br>· `IndexFaces`：「Detects faces in the input image and **adds them to the specified collection**.」＝ 只存、不搜；<br>· `SearchFacesByImage`：「first detects the largest face in the image, and then **searches** the specified collection for matching faces」＝ 只搜、不存。<br>要两件都做，后端得**自己串两支**。<br>🔴 **炸在 `OP-25`**：`§6.4` 写着「待人工补入库这个状态**目前没有入口**」。若 `Rekognize` 其实也叫了 `IndexFaces`，那入口**早就有了**，`OP-25` 是白问的；若它只叫 `SearchFacesByImage`，那 `OP-25` 成立，而且**这笔 KYC 审过了、库里却没有这张脸**——下一个人拿同一张脸来注册查不出来。<br>⚠️ **两种可能都会改到 PRD**：是前者要在 `§6.3` 状态机补一行触发源、`OP-25` 当场结案；是后者则 `OP-25` 照旧。 |

✅ **2026-09-02 结清**：Luke 答「**两支都叫**」。

⇒ **A 段成立**：`Rekognize` 后端串了 `IndexFaces` ＋ `SearchFacesByImage` 两支，
**同时做入库与查重**，与 Luke 的记忆一致。

🔴 **连带两件**：
1. `PRD_v1.4_KYCFaceSimilarity` `§6.3` 的入库状态机**漏了一个触发源** ——
   目前只写「KYC 提交，照片合格」，要补上 `Rekognize`。
2. **`OP-25` 当场结案**：`§6.4` 写「待人工补入库目前没有入口」是**基于「`Rekognize` 不入库」这个前提**；
   前提不成立 ⇒ **入口早就有了，就是 `Rekognize` 那颗钮**。

⚠️ **本条只结「叫几支 API」这件事。** 上面那两件要动 `case:04` 的 PRD，
**还没做**，落点写在这里免得掉。

🔴 **留下的方法**：官方文档只能回答「这家厂商有没有一支 API 同时做」，
**回答不了「我们的后端串了几支」**。后者只有开发知道——**本库没有平台代码，别自己推。**

出处：<https://docs.aws.amazon.com/rekognition/latest/APIReference/API_IndexFaces.html> ／
<https://docs.aws.amazon.com/rekognition/latest/APIReference/API_SearchFacesByImage.html>

---

## `C-028` · `case:27` 的验证码错误文案 ✅ 已结 —— **它真的在线上，但逐字与两边都不一样**

> 触发源：`27C` 补提示语表时（`CLI-022`）要给每条标 icon，照 `01_prd_spec_core §11.1` 的递进判据查库，当场撞上。

| 段 | 内容 |
|:-:|---|
| **A** | **通用文案库写什么**：[`../PRD_Spec/91_common_toasts.md`](../PRD_Spec/91_common_toasts.md) `#13` 收的是 `Verification code invalid`，同档第 66 行逐字写着：<br>「⇒ 收 `Verification code invalid`（**实测**）；`prd:PRD_v1.3_registrationPhStoreSelect` 里的 `Incorrect verification code, please resend` 是**拟稿、未实现**。」<br>依据是 Luke 2026-08-31 逐字「**这句我实测的，先前里面那句，有可能是我一开始写的，但实际没有按照这个实现**」。 |
| **B** | **PRD 写什么**：`PRD_v1.3_registrationPhStoreSelect.md`（当时的现行版，现已归档进 `Archive/`） `§3.4` **B 段**标题逐字是「**沿用既有（4 条，本次一个字都不改）**」，导语写「**这四条线上已经有了**」，其中第 3 条就是 `Incorrect verification code, please resend`。 |
| **C** | **冲突在哪 ＋ 什么场景会炸**：**同一句话，一边说它是线上既有、一边说它从没实现。**<br>🔴 **炸点是 icon 标错**：`§11.1` 的递进判据里，「线上既有」标 `✅`、「本 PRD 拟稿」标 `📐`，**两个 icon 给开发的指令不同**——`✅` 是「照抄，线上就长这样」，`📐` 是「这是我们拟的，上线前要核」。标成 `✅` 就等于叫开发照一句**从没上线过**的文案做。<br>⚠️ **还有第二层**：若线上真的跑的是 `Verification code invalid`，那 `27` 这一条的中文对照「验证码有误，请重新发送」也对不上库里的「验证码错误」。 |

✅ **2026-09-02 结清**：Luke 给了**线上截图**（注册／登录页，`Mobile Number` ＋ `OTP` ＋ `Login with Password`），
并裁「**照截图**」。

🔴 **线上逐字是**：`Incorrect verification code,please resent.`

⇒ **A 段那句「拟稿、未实现」是错的** —— 它**真的在线上跑**。
⇒ **B 段方向对，但逐字不对。** PRD 写的与线上差**三处**：

| # | PRD `case:27` 写的 | 线上截图逐字 |
|:-:|---|---|
| 1 | 逗号后**有空格** `, please` | **没有空格** `,please` |
| 2 | `resend`（重新发送）| `resent`（已重发）|
| 3 | 结尾**没有句点** | 结尾**有句点** `.` |

⚠️ **两句都是线上的，各管各的流程**，不是二择一：
· **注册／登录**流程 ⇒ `Incorrect verification code,please resent.`（本条，2026-09-02 截图）
· **绑定电子钱包**流程 ⇒ `Verification code invalid`（`case:32`，Luke 2026-08-31 实测）

🔴 **还没做的三件**（落点写在这里免得掉）：
1. `PRD_Spec/91_common_toasts.md` 第 66 行那句「**拟稿、未实现**」要更正 —— 本轮同批已改
2. `待评审/27.注册可选实体站展示` 的 PRD `§3.4` B 段第 3 条要改成**线上逐字**，icon 由 `📐` 改 `✅`
3. `27C` 原型的提示语表跟着改

🔴 **留下的方法**：`R-113` 那条「择一的依据是哪一句真的在线上跑」**还要再加一层** ——
**「在线上跑」也要逐字核过**。本条三处差异（空格 ／ `resend`／`resent` ／ 句点）
**每一处都会让 `HTML-013` 逐字比对失败**，而它们全都躲得过人眼。

---

## `C-029` · 归档顺序：`§四` 说「先搬再合并」，Codex 外审闸要「先合并才审得到」 ✅ 2026-09-03 已结

**A · [`../进行中/README.md`](../进行中/README.md) `§四` 写什么**

> 🔴 **一个动作，不拆。而且是在自己那条 worktree 里做，不是合并完才做。**
> `git mv 进行中/NN.需求名 待评审/NN.需求名`
> 搬完，**还在 worktree 里**：1. 跑闸　**回主库**：2. 合并进 `master`

⇒ 顺序是 **`git mv` → 跑闸 → 合并**。

**B · [`../CLAUDE.md`](../CLAUDE.md) `§十一` 那道外审闸怎么运作**

`_tools/hooks/codex_gate.py:480` 是 `target = Path(cwd) / rel` ——
**用的是 session 的 cwd**，而且 `DELIV_RE` 要求路径以 `进行中/` ／ `待评审/` 开头。
另一半是 `_tools/hooks/pre-commit` 闸②：**`git mv` 进 `待评审/` 那一刻**就查通过纪录。

**C · 冲突在哪 ＋ 什么场景会炸**

需求做在自己那条 worktree 里，而 session 的 cwd 是**另一条** worktree（或主库）
⇒ `DONE-CLAIM: 进行中/NN.xxx/PRD_v*.md` **解析不到那个档**，外审跑不起来。
要让它解析得到，只能**先把需求分支合并回 `master`**（东西仍留在 `进行中/`）
—— 而那正好与 `§四` 的顺序相反。

🔴 **两条都照做是做不到的**：
· 照 `§四` 先 `git mv` ⇒ `pre-commit` 闸② 当场挡（还没有通过纪录）
· 先拿到通过纪录 ⇒ 得先合并 ⇒ 违反 `§四`

**实证**（2026-09-03，`case:25`，`_local/codex_gate/pass/` 的第一次实跑）：
我先合并再送审，Codex 判 `CONTRADICTED` 并据此 `BLOCK`，出处指到
`进行中/README.md:88-104`。**它判对了** —— 我在讯息里写「顺序没有违反 §四」是合理化。

| 可能的处置 | 代价 |
|---|---|
| 甲 · 改 `§四`：**归档前先合并，外审在 `master` 上跑，过了再 `git mv`** | 要改流程档；`§四` 原本要序列化的是**编号表**（第 3 步），与 mv/merge 顺序其实是两件事 |
| 乙 · 改闸：`codex_gate` 支援 worktree 路径（先 `git worktree list` 再逐条试解析）| 闸要多一段路径解析；session cwd 与需求 worktree 不同条时仍要处理 |
| 丙 · 一个需求一条 session，cwd 就落在那条 worktree | 治本，但那是作业习惯不是规格，管不住 |

✅ **2026-09-03 结案：走乙，改闸不改流程。**

Luke 逐字：「**一起**」（与 `C-030` 同批裁）。

🔴 **实际动的只有一处**：`codex_gate.py` 新增 `resolve_claim()` —— cwd 找不到就照
`git worktree list` 逐条试。**`进行中/README.md §四` 一个字都没改。**

⚠️ **另一半本来就不是问题**：`_local/codex_gate/` 的 `state_dir()` 走 `--git-common-dir`
指到主库，**通过纪录本来就跨 worktree 共用**（2026-09-03 读码确认）。
先前以为要连流程一起改，是我没查到这一层。

**反例实测**：只在另一条 worktree 造一个档 ⇒ 主库 cwd 底下 `is_file()` 为 `False`、
`resolve_claim()` **找得到**并回传该 worktree 的实体路径；真的不存在的路径回 `None`。

---

## `C-030` · 外审把「原型的要求」算到 PRD 头上 ✅ 2026-09-03 已结

**A · 标准怎么写的**

[`../_tools/codex_gate/prompt_prd.md`](../_tools/codex_gate/prompt_prd.md) `:21`：

> 把「Luke 的要求」里**与这份档有关**的要求拆成一条一条。每一条到档里找落点。

⇒ **规则本来就要求分范围。**

**B · 实际怎么判的**

`case:25` 送 `PRD_v1.7` 外审，Codex 两轮都把两条**只属於原型**的要求判成 `MISSING` 并 `BLOCK`：

| Luke 的原话 | 落在哪 | Codex 判 |
|---|---|---|
| 「**闪动完的圆角要处理**」| `prototype/Html_BO_v1.2…html:1258` | `MISSING`（对 PRD）|
| 「**搜索区拉到跟表格一样宽，然后左右滚动**」| 同档 `:102`、`:115` | `MISSING`（对 PRD）|

🔴 **它自己去读了原型、也指出那两处的行号**，第二轮把我「已在原型处理、不属 PRD」那条宣称判成 `SUPPORTED`
—— **然後还是照挡**。

**C · 冲突在哪 ＋ 什么场景会炸**

`prompt_prd.md:31` 是「任何一条 `MISSING` ⇒ **BLOCK**」，而「与这份档有关」**没有给判准**。
⇒ Luke 的话只要没点名档案（多数不会点），就会被算到当下受审的那一份上。

🔴 **後果是这一类 PRD 永远过不了**：只要同一轮对话里出现过原型回馈，
审 PRD 时就必然有 `MISSING`。反过来审 HTML 时也一样 —— PRD 侧的口径要求会算到原型头上。

⚠️ **不是「PRD 少写了」**：`PRD_v1.7 §2.2.1` 明写「原型图看得出的栏位顺序与排版不在此列」，
[`../HTML_Spec/README.md`](../HTML_Spec/README.md) `:3` 明写「这条轴管『原型长什么样』……**两边不重叠**」。
两份档各自写死了分界，**把画面行为写进 PRD 反而是错的**。

| 可能的处置 | 代价 |
|---|---|
| 甲 · `prompt_prd.md` ／ `prompt_html.md` 补一条**归属判准**：画面行为／版面／交互 ⇒ 原型；口径／字段／文案／规则 ⇒ PRD。判不出来标 `N/A` 不算 `MISSING` | 要改标准档；判准写窄才不会变成万用免死金牌 |
| 乙 · 抽「Luke 的要求」时先按档案分流，只喂与该档有关的那几条 | 要改 `codex_gate.py` 的取材段 |
| 丙 · 不改，靠第 3 轮自动放行 ＋ 人看报告 | 每一份 PRD 都要烧满 2 轮才过，闸形同排队器 |

✅ **2026-09-03 结案：走甲，两份标准各补一条归属判准。**

Luke 逐字：「**甲**」「**一起**」。

**补进 `prompt_prd.md` 与 `prompt_html.md` 的 §乙**：

| 要求讲的是 | 归哪一份 |
|---|---|
| 画面长相、版面宽窄、滚动、颜色、圆角、动效、按钮点了会怎样、弹窗长相 | **原型** |
| 取数口径、字段与枚举、文案逐字、校验规则、权限点、验收场景、边界与不做 | **PRD** |

新增判定值 `N/A`（不属本档），**不触发 BLOCK**。

🔴 **`N/A` 刻意不是免死金牌**：要写出它落在同需求的**哪一份档、哪一行**；
**在那一份档里也找不到落点 ⇒ 不是 `N/A`，是 `MISSING`。**
（这一次 Codex 自己就找得到 `Html_BO_v1.2:1258`、`:102`、`:115`，
判准补上之後那三条会变 `N/A` 而不是 `MISSING`。）

⚠️ `test_codex_gate.py` 35 项复跑 **失败 0**。

---

## `C-031` · 需求原文说「按钮禁用」，PRD 说「按钮点得下去」 ✅ 2026-09-04 已结

**触发源**：`case:27` 的 `PRD_v1.4` 走 OpenRouter 送 Codex 外审，35 条判定 34 条过，
唯一 `CONTRADICTED` 就是这一条。**是真缺口，不是闸判错对象。**

**A · 需求原文写什么**

[`../待评审/27.注册可选实体站展示/需求原文.md`](../待评审/27.注册可选实体站展示/需求原文.md) `:86`（第 5.5 条）：

> 5.5 **`Login / Register` 按钮的高亮条件要加一项。** 由现行的「手机号 ＋ OTP 有效，且协议已勾选」改为「手机号 ＋ OTP 有效，协议已勾选，**且已选中一个启用中的实体站**」。**任一条不满足，按钮置灰禁用**——沿用平台既有的必填口径，不另做提示语。

**B · PRD 写什么**

`PRD_v1.4_registrationPhStoreSelect.md` `:187`（§2.5.3）：

> **2.5.3**　🔴 **但按钮不做成 `disabled`，它仍然点得下去。** 只有当「**没选中一个启用中的实体站**」这一项不满足时，点它要出 §3.4 那句 Toast。

**C · 冲突在哪 ＋ 什么场景会炸**

**「禁用」与「不禁用」正面对撞。**

🔴 **但这不是 PRD 写错。** 是 Luke 2026-08-28 亲自改的 —— 同一份 PRD 的版本记录 `:12`（`v1.2`）写着：

> `Login / Register` 由「置灰禁用」改为**「置灰但点得下去」**（§2.5）——🔴 **这一条推翻平台通用 UI 规则**，射程只限「没选到启用中的实体站」这一项。

⇒ **真正的洞是：需求原文没跟着改，PRD 也没指回去说它推翻了哪一条。**
两份档各说各的，而两边都没有指标连到对方。

**炸点**：需求原文是**业务范围契约**（[`HOWTO.md`](HOWTO.md) §三），开发照它做。
照 5.5 做成 `disabled` ⇒ **`disabled` 的按钮不派发点击事件** ⇒ `AC16` 那句 Toast **永远出不来**。
🔴 **而画面看起来完全正常**：按钮本来就该是灰的，没人看得出少了一个 Toast。

⚠️ **这一类打架 `lint_prd` 看不见** —— 它只查一份档自己长什么样，
不比对「同一个需求资料夹里另一份档说了什么」。全库没有任何闸做这件事。

| 可能的处置 | 代价 |
|---|---|
| A · 只改需求原文 5.5，加一句「已被推翻，以 PRD §2.5.3 为准」 | 最小；但 PRD 那侧仍没指回来，下一个人从 PRD 读起还是不知道推翻了什么 |
| B · 只改 PRD §2.5.3，明写「本条推翻需求原文 5.5」 | PRD 要升版；但需求原文照旧写着旧口径，开发直接读它一样会做错 |
| C · **两边都补，并开本条** | 要动三份档、PRD 升版；换到「从任一份读起都指得到对方」 |

✅ **2026-09-04 结案：走 C。** Luke 逐字：「**C**」。

**处置（三处）**：

| # | 档 | 改什么 |
|:-:|---|---|
| 1 | `需求原文.md` §二 5.5 | 原句保留不动，底下加一段推翻注记：日期、谁裁的、以哪一条为准、指向本条 |
| 2 | `PRD_v1.5` §2.5.3 的引言 | 原本只写「推翻平台通用 UI 规则」，补上**也推翻了需求原文 5.5**，并指向本条 |
| 3 | 本档 | 本条 |

🔴 **需求原文的原句刻意不删。** 它是当时真的这样要求的，删掉就查不到「本来要什么」；
照 [`../CLAUDE.md`](../CLAUDE.md) `§一` 的同一个道理 —— 留得下旧版才比得出差异。

⚠️ **这条的普遍性**：`27` 是六个重跑需求的第一个。
**只要一个需求在写 PRD 的中途被 Luke 改过口径，就可能留下同一种洞**，
而需求原文多半不会跟着改。⇒ `28`~`32` 送审时要特别看 `CONTRADICTED` 那一栏。

---

## `C-032` · 线上「协议没勾」会出一句 Toast，PRD 说「一句都不出」 ✅ 2026-09-05 已结

**触发源**：Luke 2026-09-05 给了线上注册页的提示语，要求补进 `case:27`。

**A · 线上写什么**

协议勾选框**没勾**就按 `Login / Register`，线上会出一句 Toast：
`Please agree to the privacy policy`（Luke 2026-09-05 逐字提供）。

**B · 档案写什么**

| 哪一份 | 逐字 |
|---|---|
| `待评审/27.…/Archive/PRD_v1.9…md` `§2.5.4` | 「射程只有实体站这一项。 手机号没填满、OTP 不对、**协议没勾**——**一律不出 Toast**，照旧静默置灰。」 |
| 同档 `AC17` | 「有启用中的实体站、但手机号／OTP／**协议**任一未满足，按下 `Login / Register` → **一句 Toast 都不出**，照旧静默置灰」 |
| 同档 `§2.5.2` | 「手机号 ／ OTP ／ **协议**这三项不满足时，沿用平台既有做法：静默置灰，不给任何提示。」 |
| [`../PRD_Spec/95_luke_rulings.md`](../PRD_Spec/95_luke_rulings.md) `R-193` 的**落点** | 「手机号 ／ OTP 格式 ／ **协议**任一没满足就静默返回」 |

**C · 冲突在哪 ＋ 什么场景会炸**

同一个动作，两个相反的答案。

**炸点是验收互斥**：开发照 `AC17` 写测试案例，断言「按下去没有 Toast」；
照 `§3.4` 的文案表写，断言「按下去有 Toast」。**两条一定有一条永远红**，
而红的那一条会被当成实作 bug 去追，追不到东西。

🔴 **`R-193` 那一条是自己长歪的，不是 Luke 说错**：
它的**逐字裁定那一栏只讲了手机号与 OTP**（「手机号没写或 OTP 没写按钮都是置灰不可点击的状态」），
「协议」是写落点时一起归进去的。⇒ 这是 [`../CLAUDE.md`](../CLAUDE.md) `§七` 那一类：**结论对、理由多写了一项**。

✅ **2026-09-05 结案：以线上为准，改 PRD ＋ 原型**（`ruling:R-197`）。

> Luke 2026-09-05 逐字：「**依照截图改，这个就是现实的状况，最准**」
> 「**既然现在发现，并且已经实现了，那就改 PRD+原型图**」

**处置（四处）**

| # | 档 | 改什么 |
|:-:|---|---|
| 1 | `27` 的 PRD | 升 `v1.10`：`§2.5.2` ／ `§2.5.4` 的静默名单收成「手机号 ／ OTP」；新增 `§2.5.4.1`（协议不在静默名单里）与 `§2.5.4.2`（判定顺序写死）；`§3.4` B 段补这一句并标 `↪`；新增 `§3.4.8` 写射程；`AC17` 的前提改写 |
| 2 | `27` 的客户端原型 | 升 `v1.23`：提示语表补这一句；提交判定由「协议没勾就静默返回」改成「出这一句 Toast」 |
| 3 | [`../PRD_Spec/91_common_toasts.md`](../PRD_Spec/91_common_toasts.md) | 升 `v1.4`，这一句收成 `#14`（跨需求共用，所以本 PRD 标 `↪` 不标 `✅`）|
| 4 | `R-193` | 落点补一句：「协议」那一项作废，逐字裁定本来只涵盖手机号与 OTP |

🔴 **为什么不是「开发做错了」**：Luke 明说这类调整**当初经过同意**，只是没有即时回写档案。
⇒ 判据写进 `R-197`：**已经实现、且经过同意的，改档；还没实现的，照旧是档案 ⇒ 开发。**

⚠️ **这一条与 `C-028` 是同一族的第二例**，而且更深一层：
`C-028` 打架的是**文案逐字**（`resent` 还是 `resend`），本条打架的是**行为**（出不出 Toast）。
⇒ **文案对不上时，要顺手问一句「这句话什么时候会出现」** —— 那一格才是会炸的。
