# Dino English · 看板规则与条件

本文只写**规则、口径、前置条件**。页面怎么做(文案、颜色、图表、emoji、自检)见 [`PAGE-STANDARD.md`](./PAGE-STANDARD.md)。

**数据源硬规则:只用 BigQuery。不使用 Google Analytics Data API / GA MCP。**

口径依据四份 Lark 文档(见 §2),已于 2026-08-03 全文读取并与 BigQuery 实际数据核对。**核对结论:文档是目标态,BQ 是现状,两者存在系统性偏差(见 §3)。取数前必须先验证事件名与字段,不能照文档写 SQL。**

---

## 1. 每个 HTML 看板必须展示的元信息

页头(或同等醒目位置)**必须**包含:

| 字段 | 规则 | 示例 |
| --- | --- | --- |
| Project | GCP / BigQuery 项目 | `dino-english-497507` |
| Source | 本次查询用到的 dataset(可多个) | `analytics_538991439` / `de_dwd` / `de_ads` |
| Location | BigQuery 区域 | `asia-southeast1` |
| Timezone | 与 SQL 口径一致(事件时间默认 UTC;页面写明) | `UTC` |
| Range | **日历日期**,禁止写 `30daysAgo` / `yesterday` 等相对值 | `2026-07-01 → 2026-07-30` |
| Pulled | 数据拉取完成时间(注明时区) | `2026-08-03 08:00 UTC+8` |

补充:

- Range 起止日 = 本次 SQL 实际过滤的日期(`event_date` / `install_date` / `_TABLE_SUFFIX` 等)
- 刷新数据后必须同时更新 Range 与 Pulled
- 若页面有多个时间窗(如主表 30 天、趋势近 14 天),每个区块各自标明日期范围
- 原始事件时间用 `TIMESTAMP_MICROS(event_timestamp)`;业务宽表用节点日期字段
- **埋点上线日期不同,30 天窗口普遍取不满。做任何看板前先查该事件 / area 的首日,窗口按实际可用范围写,不要硬凑 30 天**

---

## 2. 文档依据

| 文档 | 用途 | 关键内容 |
| --- | --- | --- |
| [关键链路数据 & 维度定义](https://qjphu5vphyf4.jp.larksuite.com/wiki/JWFow89j0i6L0qkxcsHj1CCypBf)(v0.1 草案,**最后编辑 2026-08-06**) | **技术健康看板唯一口径来源** | §2 通用约定(四分类终态、公共维度)、§3.1 登录注册、§3.2 支付订阅(已定稿)、§3.3 进入教室、§3.4 崩溃性能、§3.5 网络三方(**含 10% 成功采样**)、§3.6 ASR/TTS 语音(新增) |
| [埋点事件明细](https://qjphu5vphyf4.jp.larksuite.com/wiki/U9Piw7KI7i64aFkYYUkjizOppDb)(V0.24,**更新至 2026-08-06**,适用 V1.3.0+V1.4.0+V1.4.2+V1.5.1) | **产品事件字典** | 五类事件的 event_id 全量登记、属性枚举、上线 / 变更版本;§3 与历史协议的迁移关系 |
| [埋点规范](https://qjphu5vphyf4.jp.larksuite.com/wiki/O1Zuw7Hh1i6BUikpbzgjZfBJpIc)(V0.24,2026-07-28) | 命名、公共属性、上报边界、质量纪律 | §2.1 公共属性表、§2.2 传值规则、§8 自定义属性 25 Key 白名单、§9 用户标识 |
| [转化链路 A/B 实验 PRD](https://qjphu5vphyf4.jp.larksuite.com/wiki/CxFywmcZaifflGkGHbSjR3AMp4g)(V1.4.2) | A/B 漏斗与发布指标 | §7.1 实验标识、§7.4 漏斗对齐锚点、§7.5 指标口径与护栏 |

### 2.1 已知缺失的配套文档(影响看板完成度)

| 文档 | 谁需要 | 缺了会怎样 |
| --- | --- | --- |
| 《转化链路AB实验-读数与统计指南》 | #6 A/B | 样本剔除、分层、显著性、样本量、SRM 判据、取数路径全部未知,A/B 看板无法给结论 |
| 《Dino English 双端页面、类名与路由对照表》 | #7 / #8 产品漏斗 | `page_view` 的 event_id 与 `screen_view` 的 firebase_screen 映射不明 |
| 基线 PRD V1.3.0 / V1.3.2 / V1.4.0 / V1.4.1 | 全部产品看板 | 线上既有转化触点的出处 |
| 「有效学习分钟数」定义 | #9 北极星 | **四份文档中均无此定义**。原 DASHBOARDS 引用的「埋点规范 §1.2」在实际文档中不存在,该指标来源不明,已降级为待确认 |

硬规则:

- 技术健康看板与产品转化看板**分文件、分口径**,不在同一页混读
- A/B 发布主指标 ≠ 产品北极星
- **技术健康只认 `app_diagnostic`。产品事件(click / page_view / trigger / signup_result / subscription_purchase_result)明确不用于技术健康率计算**(关键链路 §3.1 B 节原文)

---

## 3. 两套事件模型(取数前必读)

BigQuery 里同时存在两套完全不同的事件体系,**互不通用**:

| | 技术诊断 | 产品事件 |
| --- | --- | --- |
| 定义出处 | 关键链路文档 | 埋点规范 + 埋点事件明细 |
| `event_name` | 固定 `app_diagnostic` | `click` / `page_view` / `trigger` / `signup_result` / `subscription_purchase_result` |
| 分类字段 | `diagnostic_area` / `diagnostic_id` / `diagnostic_step` | `event_id`(事件字典内全局唯一) |
| 结果字段 | `result` + `reason` | `is_success` + `result` |
| 回答什么 | 掉在哪段、是不是技术错误 | 用户做了什么、转化多少 |

**注意:`app_diagnostic` 不在埋点规范的五类事件里。** 它是关键链路文档单独定义的体系,埋点规范完全没写它。两套文档各管一半,不要拿埋点规范的规则去套技术诊断,反之亦然。

### 3.1 新旧模型并存(2026-08-03 实测,窗口 07-03 → 08-01)

埋点规范要求把旧的独立事件名迁到「五类 event_name + event_id」模型。**迁移只做了一半,旧事件仍是主力**:

| 规范目标 | 旧 event_name(仍在跑) | 量 | 新模型 | 量 | 状态 |
| --- | --- | --- | --- | --- | --- |
| `click` / event_id | `button_click` | 109,616 | `click` | 5,536(07-22 起) | 旧为主 |
| `page_view` / `login` | `login_page_view` | 11,694 | `page_view`+`event_id=login` | 913 | 旧为主 |
| `page_view` / `report` | `report_page_view` | 4,690 | `page_view`+`event_id=report` | 189 | 旧为主 |
| `page_view` / `subscription` | `subscription_page_view` | 1,632 | `page_view`+`event_id=subscription` | 689 | 旧为主 |
| `page_view` / `discount_offer` | `discount_offer_view` | 3,490 | `page_view`+`event_id=discount_offer` | 364 | 旧为主 |
| `trigger` / `login_result` | `login_result` | 14,790(**07-30 停报**) | `trigger`+`event_id=login_result` | 1,185 | 已切换 |
| `trigger` / `class_stage_*` | `class_stage_progress` | 167,257(**07-29 停报**) | `class_stage_start`/`_end` | 3,751 / 3,254 | 已切换 |
| `trigger` / `dino_session_*` | `dino_assistant_progress` | 35,668 | `dino_session_start`/`_end` | 575 / 500 | 旧为主 |
| `trigger` / `step_submitted` | `step_submitted` | 96,739 | `trigger`+`event_id=step_submitted` | 1,922 | 旧为主 |

规范外事件(文档未登记,实际在跑):`business_result` 11,972 · `HA_LOGIN` 431 · `vip-button-click` 361 · `ui_click` 936 · `coupon_page_view` 611 · H5 落地页系列 `landingpageDino*` 约 2 万。

### 3.2 取数纪律(由 §3.1 推出,强制)

1. **写 SQL 前先跑事件名清单**,确认要用的事件在窗口内实际叫什么、有没有停报:
   ```sql
   SELECT event_name, COUNT(*) n, MIN(event_date) d0, MAX(event_date) d1
   FROM `dino-english-497507.analytics_538991439.events_*`
   WHERE _TABLE_SUFFIX BETWEEN 'YYYYMMDD' AND 'YYYYMMDD'
   GROUP BY 1 ORDER BY n DESC
   ```
2. **跨迁移期的指标必须同时取新旧两套并说明**,只取一套会漏一半量
3. 文档里的 `reason` / `source` 枚举是**参考不是约束**,实际值以 BQ 为准(已知实现漂移见 §5 各看板)
4. 停报事件不可延续旧口径,必须换事件重建并注明两套数值不可比
5. **判失败一律双取 `fail` + `tech_fail`**,理由见 §3.3
6. **每次取数先跑一遍 §3.3 的词表哨兵**,出现表外新词就先查清楚再出数

### 3.3 两端把「失败」写成了不同的词(2026-08-07 实测)

Android 于 2026-07-29 起把失败改标 `tech_fail`,**iOS 大部分事件至今仍标 `fail`**。
而且 iOS 自己也不一致 —— 登录已经用新词,会话保持还是旧词。

窗口 07-07 → 08-05 内两端用词不一致的事件:

| `diagnostic_id` | Android | iOS |
| --- | --- | --- |
| `signature_refresh_result` | `tech_fail` | `fail` |
| `auth_refresh_result` | `tech_fail` | `fail` |
| `api_result` | `tech_fail` | `fail` |
| `appsflyer_conversion_result` | `tech_fail` | `fail` |
| `appsflyer_deeplink_result` | `tech_fail` | `fail` |
| `push_token_result` | `fail` / `tech_fail` | `fail` |

**这是最危险的一类坑:只认一个词,会静默丢掉整整一个平台的失败量 —— 查询不报错,页面照样出数,成功率凭空变好看。**

所以:

```sql
-- 对
COUNTIF(r IN ('fail','tech_fail')) AS failed
-- 错:iOS 的失败会全部消失
COUNTIF(r = 'tech_fail') AS failed
```

取数脚本里把它收成一个常量(`tools/gen-auth-data.py` 的 `FAILED`),**不要就地写字面量**。

另外 `result` 还有表外的取值:`skip`(`push_bind_result` 一万条、`appsflyer_deeplink_result` 一千多条)、
`cancel`(`purchase_client_result`、`push_bind_result`)。这些**既不是成功也不是失败**,
做相关看板前必须先问清楚语义,不要想当然归类。

哨兵查询(`tools/gen-auth-data.py` 每次跑都会执行):

```sql
SELECT (SELECT value.string_value FROM UNNEST(event_params) WHERE key='diagnostic_id') did,
       platform, (SELECT value.string_value FROM UNNEST(event_params) WHERE key='result') r,
       COUNT(*) n
FROM `dino-english-497507.analytics_538991439.events_*`
WHERE _TABLE_SUFFIX BETWEEN 'YYYYMMDD' AND 'YYYYMMDD' AND event_name='app_diagnostic'
GROUP BY 1,2,3 HAVING n > 20
```

---

## 4. 环境与取数条件(BigQuery)

| 项 | 值 / 要求 |
| --- | --- |
| GCP Project | `dino-english-497507` |
| Location | `asia-southeast1` |
| 取数方式 | BigQuery SQL;本地用 MCP `bigquery`(Google MCP Toolbox + ADC) |
| 凭证 | ADC:`gcloud auth application-default login` |
| 日表结算 | 查询用 `events_YYYYMMDD`;当日与前一日为 `events_intraday_*`,**不纳入看板** |
| 静态页 | 数据内嵌页面;更新 = 跑 SQL → 改 `DATA` 常量 → 改 Range / Pulled |
| 禁止 | Google Analytics Data API、`user-analytics-mcp`、`run_report` 等 GA 实时报表接口 |

### 4.1 dataset

| Dataset | 用途 | 实测 |
| --- | --- | --- |
| `analytics_538991439` | Firebase / GA4 导出日表 `events_YYYYMMDD` | 日均 4~8 万行 |
| `de_ods` | 业务原始 | `user` 14,733 · `user_profile` 14,733 · `payment_order` 2,316 · `payment_event` 293 · `web_order` 123 · `analytics_event_outbox` 122,223 |
| `de_dwd` | 明细 | `dwd_firebase_event_di` 130 万 · `dwd_user_identity_map_di` 108,414 · `dwd_funnel_user_di` 32,422 · `dwd_appsflyer_installs_di` 32,422 · `dwd_payment_env_resolved_di` 2,871 · `dwd_retention_cohort_user_di` 14,695 |
| `de_dws` | 汇总 | `dws_funnel_cohort_di` 1,340 · `dws_retention_result_di` 20,669 · `dws_ops_metric_di` 1,733 · `dws_portrait_*` |
| `de_ads` | 看板宽表 | `ads_funnel_dashboard_di` 1,340 · `ads_retention_dashboard_di` 20,504 · `ads_tableau_funnel_user_di` 32,422 |
| `apps_flyers` / `google_ads_*` | 归因 / 广告导出 | 按需 |

`*_legacy` 后缀表为历史快照,**不要用于看板**。

### 4.2 `app_diagnostic` 各 area 可用量(07-03 → 08-01 实测)

| area | 量 | 首日 | 对应看板 |
| --- | --- | --- | --- |
| `analytics` | 69,958 | 07-15 | #1(`app_context_sync_result`)、A |
| `attribution` | 31,086 | 07-14 | 归因 |
| `auth` | 26,551 | 07-14 | #1、#5 |
| (无 area) | 25,048 | 07-16 | 待归类 |
| `push` | 21,136 | 07-16 | #5 |
| `network` | 14,936 | 07-20 | #5 |
| `third_party` | 11,828 | 07-20 | #1(`sdk_auth_launch_result`)、#5 |
| `classroom` | 8,791 | 07-22 | #3 |
| `purchase` | 3,129 | 07-16 | #2 |
| `deeplink` | 2,706 | 07-16 | #5 |
| `performance` | 363 | 07-27 | #4 |
| `routing` | 10 | 07-25 | — |

**首日要按 `diagnostic_id` × platform 查,不能只按 area。**同一个 area 下不同 id 的上线日能差两周,
两个平台也各上各的。登录两段 + ID 同步附注项实测:

| `diagnostic_id` | Android 首报 | iOS 首报 |
| --- | --- | --- |
| `auth_login_result` | 07-28 | 07-27 |
| `sdk_auth_launch_result` | 07-29 | 07-29 |
| `app_context_sync_result` | 07-23 | 07-16 |

```sql
SELECT (SELECT value.string_value FROM UNNEST(event_params) WHERE key='diagnostic_id') did,
       platform, MIN(event_date) first_day, COUNT(*) n
FROM `dino-english-497507.analytics_538991439.events_*`
WHERE _TABLE_SUFFIX BETWEEN 'YYYYMMDD' AND 'YYYYMMDD' AND event_name='app_diagnostic'
GROUP BY 1,2 ORDER BY 1
```

由此推出两条硬规矩:

1. **窗口标事件自己的首报日,不是查询区间。**写「30 天」而实际只有 8 天,读者会把灰度期的爬坡量当成日常水位。
2. **灰度期的总量不是水位。**实测把 30 天窗口只往后挪 3 天,段②总量从 672 涨到 1,545 —— 那是铺量,不是增长。凑不满窗口就**不要算环比**。

### 4.2.1 最新一张日表还会被回填

实测:2026-08-03 12:15 取的 08-01 是 290 条,08-04 09:10 重拉变 301 条(+11),主指标从 95.21% 掉到 94.74%。

所以窗口终点取**最新一张已结算日表**(`events_intraday_*` 一律排除),并且**这一天要在页面上标成暂定** ——
不删数,但不许当定论。做法见 PAGE-STANDARD §8.2。

### 4.3 原始事件 SQL 约定

```sql
FROM `dino-english-497507.analytics_538991439.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20260703' AND '20260801'

TIMESTAMP_MICROS(event_timestamp) AS event_time_utc
event_date   -- STRING YYYYMMDD

(SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'diagnostic_id') AS diagnostic_id
```

缺字段 / 空表时:表不存在、分区无数据、或 `event_params` 无该 key → 页面注明「条件未满足」,**不编造数**。

---

## 5. 口径总则

### 5.1 终态四分类(关键链路 §2.2,技术健康的地基)

每条链路终态强制分四类,**不要只有成功 / 失败**:

| result | 含义 | 是否进技术分母 |
| --- | --- | --- |
| `success` | 成功 | ✅ 分子 |
| `tech_fail` | 技术失败(网络 / 超时 / 5xx / 崩溃 / SDK 错误) | ✅ 分母,技术健康主指标只盯这个 |
| `user_abort` | 用户主动取消 / 返回 | ❌ 单独切片 |
| `rejected` | 服务端业务拒绝 / 不满足条件 | ❌ 单独切片 |

**技术成功率 = `success` ÷ (`success` + `tech_fail`)**

`reason` 也要预先标「技术类 / 非技术类」,方便只看技术失败。

**例外:支付链路(§3.2)已定稿不迁四分类**,维持 `success` / `fail` / `cancel` / `deferred` / `skip` 五值,公式见 #2。做支付看板时不要套四分类。

### 5.2 公共维度

关键链路 §2.3 要求所有链路支持:版本 · 平台 · 网络类型 · 地区 · 是否会员 · 用户 / 设备标识。

字段来源(埋点规范 §2.1):

| 维度 | 取法 | 注意 |
| --- | --- | --- |
| 版本 | `app_info.version` | 顶层字段 |
| 平台 | `platform` | 顶层,值为 `ANDROID` / `IOS` |
| 地区 | `geo.country` | **顶层字段,不是 event_params**;研发不上传 country 自定义参数 |
| 用户 | `user_id`(= 业务 uid) | **顶层字段,不在 event_params**;`app_diagnostic` 另有 `uid` 参数 |
| 设备 | `device_id`(params) / `user_pseudo_id`(顶层) | 两者不等价 |
| 网络类型 | `network_type`(params) | 枚举 wifi / 2g / 3g / 4g / 5g / offline |
| 是否会员 | `is_premium`(params) | 规范未列为公共属性,但实际在报 |

`trace_id` 尚未落地(关键链路 §2.4 待讨论),因此**无法还原单次链路**,只能靠 area / id / step + result + reason 聚合。客诉排查类需求目前做不到。

### 5.3 读数纪律(埋点规范 §7 + §2.3)

- 分析主键优先 `uid`;登录前后合并见 `de_dwd.dwd_user_identity_map_di`
- **PII 不作为看板展示或筛选来源**;`result` 不上传原始堆栈、用户输入、手机号、邮箱、Token
- **订阅成交以服务端 `subscription_purchase_result` 为准**;客户端 `subscription_checkout_result` 与支付诊断 `success` 均 ≠ 营收
- 注册成功以服务端完成账号创建和绑定为准;三方授权成功但未建号应为 `is_success=false`
- `appsflyer_id` **已于 2026-07-28 从事件属性中删除**,归因改由服务端用户表 `appsflyer_id` ↔ `uid` / `device_id` 映射
- AppsFlyer `purchase` 仅 `success` 且 `initial_purchase` 时回传,续费不回传;收入 / LTV / 续费看 `subscription_purchase_result`
- 不重复计入 Firebase 自动事件(`first_open` / `app_open` / `session_start`)

### 5.4 健康分档与着色标准(所有看板通用)

数值本身不说明好坏,**分档由本节定义,看板只负责按档上色**。首次落地于 [`health-auth.html`](./health-auth.html),后续看板照抄。

#### 分档阈值

作用对象只有**技术成功率**(§5.1 的 `success` ÷ (`success` + `tech_fail`)):

| 档 | 区间 | 浅色 | 深色 | 用在哪 |
| --- | --- | --- | --- | --- |
| 危险 | < 95% | `#e03131` | `#ff6b6b` | 进度条填充、百分比数字 |
| 需关注 | 95% – 99% | `#fab219` | `#fab219` | 同上 |
| 健康 | ≥ 99% | `#0ca5b8` | `#22c3d6` | 同上 |
| 不判档 | 分母无失败样本 | 中性灰 | 中性灰 | 同上 |

小字号(≤ 14px)另用深一档的文字色以保 4.5:1 对比度:危险 `#c92a2a` / 需关注 `#8a5b00` / 健康 `#0b7d8c`;大字号(≥ 24px)用表内色值即可(≥ 3:1)。

#### 三条强制规则

1. **分母里没有失败样本 → 不判档,中性灰。** 100% 只说明窗口内没有失败记录,不等于健康。典型:`sdk_auth_launch_result` 按事件定义就记不到失败(§6.1.1 段①);`app_context_sync_result` 的登录触发只有 iOS 上报(附注项)。这两处涂绿/涂青就是虚假安全感。
2. **分子恒为 0 的段不算成功率,显示 `—`。** `auth_login_result` 的 `authorization` 段只在 `user_abort` / `tech_fail` 时上报,没有 `success` 记录;若照算会得到「0.00% 危险」,是假的。
3. **只有技术成功率能上分档色。** 放弃率、拒绝率、字段覆盖率、耗时 P50/P95 一律不着色 —— 它们不是健康指标,`user_abort` / `rejected` 本来就不进技术分母。

#### 事件结果构成的颜色(图表与归因表)

与分档色共用同一套,不另起一套:

| result | 色 | 说明 |
| --- | --- | --- |
| `success` | 青(同「健康」) | 堆叠柱的成功段 |
| `user_abort` | 琥珀(同「需关注」) | 非技术,单独切片 |
| `tech_fail` | 红(同「危险」) | 技术健康主指标只盯这个 |
| `rejected` | 橙 `#ec835a` | 业务拒绝,非技术 |

#### 呈现纪律

- **页面其余部分只有黑白灰,有颜色的地方一定在说数据。**章节号、导航、边框、表头不许用彩色
- 颜色不得单独承载信息:状态一律「色点 + 文字」,百分比旁边必须有数值
- 看板顶部必须有一条**颜色说明 bar**,写明三档阈值与灰档含义;bar 用连续渐变(红 → 琥珀 → 青),横轴按真实百分点作图,轴起点若不是 0 必须标注
- 浅色 / 深色两套色值都要给,深色不能由浅色自动反转

#### 每个技术健康看板必备的四个组件

文档「整体看板 & 播报」+ §3.x 专属维度推出的硬要求,#1 已落地,后续看板照做:

1. **播报行** —— 一行给出「量 · 技术健康率(环比) · 关键耗时 P95 · Top 技术失败原因」。环比取不到时显式写不可用及原因,不留空。
2. **版本对照** —— 默认按版本切片对比**新版 vs 上一版**(每天 14:30 过版本),关键指标成对给出 + 差值(pp)。不是把版本混在一张维度表里。
3. **漏斗** —— 只对**同一事件、同一分母**的链路画漏斗;跨事件/跨窗口的段落不得叠成漏斗(#1 两段就不构成漏斗,真漏斗在段② 内部)。左对齐条 + 灰色收窄楔形,转化率与流失原因标在楔形上。
4. **归因面板(主指标非「健康」时强制)** —— 见下。

##### 4. 归因面板:主指标只要不是「健康」,就必须当场解释为什么

**规则:主指标落在「需关注」或「危险」档时,页面必须紧跟一块归因面板。**只标红不解释,等于把定位工作丢给读者;present 时第一个问题必然是「为什么」,答不上来这页就白做。

面板固定回答四问,顺序不变:

| # | 回答什么 | 怎么呈现 | #1 的实例 |
| --- | --- | --- | --- |
| 1 | **失败由什么构成** | 全部 `tech_fail` 按 `reason` 归一到 100% 的堆叠条 + 图例带次数 | 30 次 = signature_failed 9 / unavailable 9 / unknown 6 / server_error 3 / sdk_timeout 2 / network_error 1 |
| 2 | **集中在谁身上** | 每个主因一行「谁 · 何时 · 所以」;「谁」必须下钻到**平台 × 方式 × 入口**级别,不能停在 reason | 三个主因各占 30%/30%/20%,分别 100% 落在 Android×google×welcome、Android×google 授权段、iOS×apple 授权段 —— 前三项占 80% |
| 3 | **是不是某一天造成的** | 尖峰日单独拎出:当日成功率 vs 其余天成功率 | 08-01 单日 16 次(53%),当天 92.63%;07-27→07-31 为 96.03% —— **是这一天把窗口拖过分档线** |
| 4 | **跟别的链路有没有同源** | 显式写出跨看板/跨段的因果,并指向对应小节 | 登录段的 signature_failed 与 §5 `signature_refresh` 同日崩到 19.4% **同源**,是签名机制故障外溢 |

硬要求:

- **主因的「谁」必须是可执行的**:能直接说出该找哪端、哪个登录方式、哪个入口。写到 `reason` 就停等于没归因。
- **区分「集中」与「普遍」**:前三因占比 ≥ 70% 就要明说「不是普遍性劣化」,否则读者会默认全线崩。
- **尖峰日必须单独算**:给出剔除尖峰日后的成功率,让人看到基线水位。
- **文档外的 `reason` 在归因面板里也要标 ✳**,与失败归因表口径一致。
- 面板用左侧危险色标条 + 白底,不整块铺红 —— 铺红会和分档色抢注意力。

#### 开放项

`health-auth.html` 现状:危险 46 格、需关注 25 格、灰 16 格、**健康 0 格** —— 凡有失败样本的指标没有一个到 99%。是照实保留(说明现状确实不健康),还是把健康线放宽到 ≥ 98%(`auth_login` 98.28%、`backend_exchange` 小计 98.17% 会转青),**待定**。改动只涉及阈值一处。

---

## 6. 看板清单与完成条件

### 6.1 技术健康(口径来源:关键链路文档)

| # | 看板 | 主指标 | BQ 条件与实测 | 状态 |
| --- | --- | --- | --- | --- |
| A | 总览 + 播报 | 每链路:量 · 技术健康率(环比)· 关键耗时 P95 · Top 失败原因;按版本对比 | 各 area 汇总,须等各分页口径定稿 | 待做 |
| 1 | 登录注册健康 | 两段技术成功率 + ID 同步附注 | 见 6.1.1 | **已完成** · 一页两列对照:[health-auth.html](./health-auth.html)(数据 2026-08-07,口径已按 08-06 改稿修订) |
| 2 | 支付订阅健康 | load / purchase / restore 三段 | `area='purchase'` 3,129 条 | **已完成** · 一页两列对照:[health-purchase.html](./health-purchase.html)(数据 2026-08-07,样本: 加载 4.8k / 购买 674 / 恢复 369) |
| 3 | 进入教室健康 | 点击 → 就绪 | `area='classroom'` 8,791 条 | **已完成** · 一页两列对照:[health-classroom.html](./health-classroom.html)(数据 2026-08-07,WebView/RTC路径) |
| 4 | 崩溃 / 性能 | crash-free / ANR;冷启动;就绪;内存 | `area='performance'` 仅 363 条;Crashlytics 未入 BQ | 阻塞 |
| 5 | 网络 & 三方 | 请求成功率(剔业务 4xx) | `network` 14,936 + `third_party` 11,828 + `deeplink` 2,706 + `push` 21,136 | 待做 |

#### 6.1.1 登录注册健康(#1)

> **2026-08-07 口径修订。**关键链路文档 2026-08-06 改稿,明确写了 `app_context_sync_result`
> 「**这个和登录流程不存在联系**」「**不阻塞任何登录流程**」,它是冷启动同步 Firebase ID / AppsFlyer ID 用的。
> **登录因此从三段改回两段**,该事件降为附注。
> 本项目此前把它当「登录第三段」并作为头号严重问题上报,是照旧稿做的 —— 已在 `health-auth.html` 更正。

**登录本身两段**,分属两个不同的 `diagnostic_area`(这是最容易漏的点):

| 段 | `diagnostic_id` | `area` | `step` |
| --- | --- | --- | --- |
| ① 三方授权 UI 拉起 | `sdk_auth_launch_result` | **`third_party`** | `authorization` |
| ② 登录授权 / 换 session | `auth_login_result` | `auth` | `authorization` / `backend_exchange` |

附注(**不属于登录链路,不进登录成功率**):

| | `diagnostic_id` | `area` | `step` |
| --- | --- | --- | --- |
| ID 同步 | `app_context_sync_result` | **`analytics`** | `context_sync` |

实测(2026-07-07 → 08-05,末日暂定):

| 指标 | Android | iOS |
| --- | --- | --- |
| ① 授权页拉起 | 1,531 条 · 99.93%(**只有 1 次失败,不可信**) | 361 条 · 100%(零失败记录) |
| ② 登录换 session | 1,949 条 · **94.60%** | 619 条 · **89.51%** |
| ② 用户自己放弃 | 445 次(22.8%) | 131 次(21.2%) |
| ② 后端换登录态耗时 | P50 8.79s · P95 26.3s | P50 7.87s · P95 37.6s |
| 附:ID 同步(登录/注册触发) | **0 条** | 1,118 条 |
| 附:ID 同步(冷启动等) | 4,693 条 · 失败 278 | 6,870 条 · 失败 136 |
| 签名刷新(暂挂) | 79,241 条 · **19.0%** | 7,716 条 · 46.4% |

**目前无判别力 / 需澄清的地方:**

- **段① 接近 100%,不可信。** Android 1,531 次里只有 1 次失败,iOS 361 次零失败。按文档判定口径「UI 已呈现即算成功;未呈现但 SDK 成功则不上报」,失败只在「未呈现且 SDK 失败/取消」时才报 —— 但光「用户取消」就不可能只有这么点。文档的三态判定(`presented`/`notPresented`/`unknown`)**只写了 iOS 怎么实现**,Android 侧是否实现要问。
  判据用**失败率**不用「恰好等于 0」:实测冒出一条迟到的失败记录就会让「零失败」判据失效,把灰色的「不可信」翻成绿色的「健康」。见 PAGE-STANDARD §3.2。
- **附注项两端不一致,但文档自己前后打架。** 正文说「和登录流程不存在联系」,**字段表却仍写着 `source=login_success | signup_success`**,示例 JSON 也是这个值。实际 Android 这两个触发点 0 条、iOS 1,118 条。
  **该确认的是「这个触发点还要不要」,不是直接判 Android 漏埋。**
  数据佐证新口径:九成触发来自 `cold_start`(8,570)与 `foreground_resume`(2,993),登录/注册触发只占 9.6%。

口径:

- **拉起成功率** = `success` ÷ (`success` + `tech_fail`),`user_abort` 不进分母。**该事件故意不带 `duration_ms`**(避免把用户停留授权页时间误读为拉起耗时)
- **登录成功率**:`result` 五值 `success` / `tech_fail` / `user_abort` / `rejected` / **`deferred`**(Kakao 补绑手机号 `phone_binding_required`,窗口内为 0)。**文档要求按 `target` 拆段看**,`target` 枚举:`apple_sdk` / `google_sdk` / `kakao_sdk` / `facebook_sdk` / `auth_login` / `sms_login` / `kakao_bind_phone`
- **ID 同步(附注项)**:`result` 只有 `success` / `fail`(不是 `tech_fail`);`source` 文档字段表只写 `login_success` / `signup_success`,**实际主力是 `cold_start` 8,570 条与 `foreground_resume` 2,993 条**。按新口径它不进登录成功率,做看板时按 source 切片单独看
- **注册 `signup_result` 的登录方式字段两端叫法不同**:文档迁移表写「`signup_method` 统一为 `method`」,但实测**只有 `web_h5` 与 `platform` 为空的行用了新名**(2,907 条),Android / iOS 仍是 `signup_method`(13,338 条)。必须 `COALESCE(method, signup_method)` 双取。另外 `platform` 大小写不统一(`android`/`Android`、`ios`/`iOS`),要 `LOWER()` 归一
- **`signup_result` 的 iOS 侧已停报**:最后一条 2026-07-31(Android 仍在报)。两端量**没有可比性**,页面必须标出断报区间,不能直接比大小
- `authorization` 段**只在失败 / 放弃时上报,无 `success` 记录**。登录尝试数 = `backend_exchange` 全量 + `authorization` 失败量
- 专属维度:`auth_method`(google / phone / facebook / kakao / apple) × `auth_entry_source`(onboarding / welcome / welcome_first)
- 耗时只取 `backend_exchange` 且 `result='success'` 的 `duration_ms`
- 注册用 `signup_result`(独立 event_name),只有 `is_success` 无 `reason`,只能回答「成没成」;落地页场景该字段缺失,须单列未上报量
- 产品侧登录漏斗(`page_view`/`login`、`click`/`login_*`、`phone_code_request_result`、`login_otp_submit`、`phone_binding_result`)**不用于技术健康率**,只用于 #7

已知实现漂移:`authorization` 段实际出现 `reason=interrupted` / `unavailable`,均不在文档枚举(文档为 cancelled / token_missing / no_presentation_anchor / nonce_generation_failed / sdk_timeout / provider_not_registered / unknown)。

着色按 §5.4:段① 与 ID 同步附注项的登录触发部分**失败少到不可信 → 中性灰不判档**(判据用失败率,不用「恰好等于 0」);`authorization` 段四个 `*_sdk` 目标**无 `success` 记录 → 成功率显示 `—`**,不得算成 0.00%。

2026-08-04 重拉后新增的实测结论(均已落到 `health-auth.html`):

| 结论 | 证据 | 影响 |
| --- | --- | --- |
| 段① 无判别力**指向 Android** | 604 条中 Android 552 条全 `success`;文档 A1 的 `presented/notPresented/unknown` 三态观测只描述 iOS | 该问 Android 是否实现「未呈现」判定,不是问「分支会不会上报」 |
| **布尔字段类型双端不一致** | `is_new_user` / `membership_seeded` / `has_onboarding_payload`:Android 报字符串 `"true"/"false"`,iOS 报整数 `1/0` | BigQuery 落 `string_value` 与 `int_value` 两列,**取数必须双取**,否则静默丢一端 |
| 入口维度缺两类 | `auth_entry_source` 实际只有 `onboarding`/`welcome`/`welcome_first`;文档 §3.1 要求含**深链、被踢回** | 「签名刷新失败 → 被踢回重登」的影响无法量化 |
| `reason` 枚举大面积未验证 | authorization 段 7 个枚举只出现 3 个;backend_exchange 段 9 个只出现 4 个 | 未出现 ≠ 没发生,与段① 同类问题,需逐条确认可触发性 |
| 新版 1.5.0 登录更差、会话更好 | 段② 86.30%(63/73) vs 1.4.2 95.98%(477/497),低 9.67pp;但 `signature_refresh` 1.5.0/Android 53.03% vs 1.4.2/Android 21.17% | 1.5.0 仅 109 条,放量后复核;需确认是否为已知取舍 |
| **数据会追平** | 08-03 12:15 取数时 08-01 为 290 条,08-04 09:10 重拉为 301 条(+11 迟到事件),主指标 95.21% → **94.74%**,跌破 95% 分档线 | 发版当天/次日的数不作最终结论,隔日复核 |
| **登录段的 `signature_failed` 与 §5 签名刷新同源** | 9 次 `signature_failed` 全部 Android×google×`welcome` 入口,8 次在 08-01,与 `signature_refresh` 当天崩到 19.4% 同日;08-01 单日贡献 16/30 次技术失败,当天 92.63% vs 前五天 96.03% | 主指标跌破 95% 是签名故障外溢的连带结果,**不是登录链路整体退化**;修 #5 的签名问题应同时抬升 #1 |
| `is_premium` 客户端存在但登录事件没带 | 同 `area=auth` 的 `signature_refresh_result` 有 131 条带 `is_premium`,`auth_login_result` 796 条为 0 | 推动时应说「登录事件补带」,不是「客户端补字段」 |

**`signature_refresh` / `token_refresh` / `unauthorized` 虽然 `area='auth'`,但按文档语义属于 §3.5 网络三方(鉴权刷新与 401 处理),归 #5。** 当前临时放在 `health-auth.html` 第 2 节,#5 建成后迁走。

#### 6.1.2 支付订阅健康(#2)

关键链路 §3.2 已于 2026-07-29 全部定稿,无开放待确认项。三段:

| 段 | `diagnostic_id` | `step` | 成功率口径 |
| --- | --- | --- | --- |
| 加载 | `paywall_load_result` | `load` | `success` ÷ 全部;每次打开只报 1 条 |
| 购买 | `purchase_client_result` | `storekit_purchase` | `success` ÷ (`success` + `fail`) |
| 恢复 | `restore_client_result` | `restore` | `success` ÷ (`success` + `fail`);`skip` 单独看 |

硬标准:

- `area='purchase'`;`source` **固定 `paywall`**(含 WinBack / 会员页),入口只走 `params.target`
- **不迁四分类**,维持五值 `success` / `fail` / `cancel` / `deferred` / `skip`;技术失败率**只看 `fail`**,`cancel` / `skip` / `deferred` 单独切片
- 绑他号 = `fail` + `reason=bound_other_account`(**不是 `rejected`**)
- 购买段 `target` 用入口短码,与 `subscription_checkout_start.source` 同枚举;下单透传串不得当 target
- `reason` 枚举:load `network_error` / `billing_unavailable` / `empty_products`;purchase `storekit_failed` / `product_unavailable` / `purchase_in_progress` / `verification_unconfirmed` / `bound_other_account`;restore `no_restorable_purchase` / `offline` / `verification_failed`
- 平台差异:iOS load 成功可报 `target=member|purchase`,Android 可只报 `purchase`;`restore` 的 `not_logged_in` 为 Android-only
- 成交信服务端 S2S,客户端诊断 `success` ≠ 营收
- 三段诊断**无 SKU**(SKU 只在产品事件里),入口 × SKU 下钻做不了

#### 6.1.3 进入教室健康(#3)

- `area='classroom'`;**分母 `class_enter_click`**,分子 `class_webview_load_success` / `class_agora_connect_success`
- 失败:`class_enter_failed`(`invalid_url` / `network_error`)、`class_webview_load_failed`(`load_timeout` / `load_fail`)、`class_agora_connect_failed`(`rtc_disconnected` / `rtc_failed` / `rtc_error`);均 `result=tech_fail`,原始错误码放 `description`(如 `error_-1017`)
- 用户主动退出:`class_user_exit`,`result=user_abort`
- 耗时:`duration_ms` 合并在 `class_webview_load_success`,口径 = 点击 → WebView `onPageFinished`,**不再有独立耗时事件**
- **RTC 成功以 `onSessionStarted` / `onLocalUserRegistered` 为准,不是 `joinChannel` 返回 `ERR_OK`**
- `source` 枚举:`home_button` / `course_list` / `learning_path` / `theme_course` / `teacher_select` / `deeplink`;空字符串为兜底,不应出现
- 文档 §6 有 iOS 实测日志,另有表格未登记的 `classroom_enter_result` / `classroom_rtc_result` / `classroom_webview_start_loading`,做看板时需确认是否纳入

#### 6.1.4 崩溃 / 性能(#4)· 阻塞

- `cold_start_result`:`duration_ms` = 进程启动 → 首帧;`target` 为首个可见 Activity(当前 `SplashActivity`),**不含 Splash → MainActivity 路由时间**,端到端需结合 `page_ready_result(target=home)`
- `page_ready_result`:`target=home` / `login`;失败走 `result=tech_fail`;`rendered=false` 时 `duration_ms` 退化为 `data_ready_ms`
- `mem_snapshot`:`total_pss_kb` / `java_heap_kb` / `native_heap_kb` / `mem_tier` / `app_foreground`;`target=home(phase=enter)` / `classroom(phase=enter/exit 配对)`,**系统直接杀进程时 exit 缺失,配对分析要允许缺失**
- 后台预拉起记 `result=rejected` + `reason=background_start`,不带 `duration_ms`
- **崩溃 / ANR 走 Crashlytics,未入 BQ → 页面标缺口**
- 文档明写待确认:SplashActivity 到其他页面是数据空白地带
- **阻塞原因:`area='performance'` 窗口内仅 363 条(07-27 首日),样本不足以出结论。等量起来再做**

#### 6.1.5 网络 & 三方(#5)

- 主指标:请求成功率(**剔业务 4xx**)
- 覆盖:各接口成功率 / 耗时、**鉴权刷新与 401 处理**、深链解析、三方 SDK 初始化
- 数据源:`area='network'` 14,936 + `third_party` 11,828 + `deeplink` 2,706 + `push` 21,136,以及从 #1 迁入的 `auth` 域会话保持三段
- 专属维度:接口(endpoint) × 错误类型 × SDK

### 6.2 产品转化 / A/B

| # | 看板 | 主指标 | BQ 条件与实测 | 状态 |
| --- | --- | --- | --- | --- |
| 6 | A/B 实验总览 | 进组新装 7 日订阅支付成功率(B vs A);SRM;护栏 | **前置条件不满足,见 6.2.1** | 阻塞 |
| 7 | 新手转化漏斗 | PRD §7.4 锚点逐层到达率 | `dwd_funnel_user_di` 32,422 | **已完成** · [funnel-onboarding.html](./funnel-onboarding.html)(数据 2026-08-07) |
| 8 | 支付产品漏斗 | 曝光 → checkout → 成功/取消/失败 | 见 6.2.2 | **已完成** · [funnel-payment.html](./funnel-payment.html)(数据 2026-08-07,数据质量问题已标注) |
| 9 | 有效学习 / 北极星 | 有效学习分钟数 / 周 | **定义缺失**,见 §2.1 | 阻塞 |

#### 6.2.1 A/B 实验总览(#6)· 阻塞

PRD §7.5 口径:

- **主指标(唯一发布依据)** = 进组后 **168 小时**内产生 `subscription_purchase_result(result=success)` 的设备数 ÷ 进组设备数。SKU 含免费试用期时以订阅开通为准
- 归属:未登录按 `device_id`,注册 / 登录成功后服务端绑定 `uid`;Firebase 事件通过顶层 `user_id` 关联。**PRD 明确不设任何 Firebase User Properties**
- 护栏(任一显著恶化即暂停放量):登录 / 注册失败率、分组成功率(fallback 占比)、崩溃率、首课完课率、D1 / D7 新装留存、7 日退订退款率
- §7.4 给了完整的 A/B 漏斗对齐锚点表(进组 / 登录页曝光 / 登录方式 / 登录结果 / 注册 / Onboarding 完成 / 计划页 / Paywall / 首课 / 报告 / 发起支付 / 支付取消失败 / 支付成功),分母统一为进组设备

**三条阻塞(2026-08-03 实测):**

1. **唯一真相源不在 BigQuery。** PRD §7.1 规定服务端分组明细表同步 BQ、作为圈样本的唯一名单。实际扫遍 `de_ods` / `de_dwd` / `de_dws` / `de_ads` **没有任何实验 / 分组表**。事件 `trigger`+`event_id=experiment_group_assign` 仅 691 条(channel = a / b / fallback),PRD 明说它只用于校验分组量与 SRM,**不是真相源**
2. **分子样本过小。** `subscription_purchase_result` 窗口内 2,801 条,其中 `result='success'` 仅约 42 条。以 691 进组设备为分母,任何 B vs A 差异都不可能显著
3. **读数指南缺失。** 样本剔除、分层、显著性、样本量、SRM 判据全部未知(见 §2.1)

**结论:在分组明细表进 BQ 且积累足够样本之前,#6 只能做「SRM 与埋点完整性监控页」,不能做发布决策页。**

#### 6.2.2 支付产品漏斗(#8)

- 锚点:`page_view`+`event_id=subscription` → `trigger`+`event_id=subscription_checkout_start` → `subscription_checkout_result` → `subscription_purchase_result`
- **成交只信 `subscription_purchase_result`**;`result` 为 `pending` / `success`,`type` 为 `initial_purchase` / `renewal`,同一 `order_id` 可先 pending 后 success
- 该事件带 `price` / `currency`(USD)/ `cycle` / `channel` / `content_id`(SKU),**可直接算收入与 ARPU**;`transaction_id` / `original_transaction_id` 用于关联续费
- 已知数据质量问题:2,801 条中 **2,426 条 `result` / `type` / `cycle` / `channel` 全为空**(仅 `price` 有值,合计 38,262),疑为旧口径并存。**做看板前必须先查清这 2,426 条属于哪套口径,否则收入会算错**
- `channel` 实际出现 `Apple` / `Google`(旧)与 `apple_iap` / `google_play`(新)两套写法,须归一
- 前端取消 / 失败原因看 `subscription_checkout_result.result`,该字段**不设统一枚举,各端原样上报**(实测有 `user_cancel` / `storekit_unknown` / `1` / `5`),聚合前需清洗

---

## 7. 更新检查清单(每次改数据)

登录看板已脚本化,一条命令重新生成(窗口自动取到最新已结算日表):

```bash
python3 tools/gen-auth-data.py        # 默认 30 天,可传天数
```

只改写 `auth-data.js`,页面全部由它推导。其余看板按下面走:

1. 用 BigQuery SQL(或 MCP `bigquery`)重拉,禁止 GA API
2. **先跑 §3.2 的事件名清单**,确认事件在窗口内的实际名称与停报情况
3. **跑 §3.3 的词表哨兵**,确认没有表外新词、两端用词不一致的都已双取
4. **按 `diagnostic_id` × platform 查首报日**(§4.2),窗口标事件自己的首日,不是查询区间
5. 确认 dataset / 表 / 分区与 Range 一致;不用 `*_legacy` 表、不用 `events_intraday_*`
6. 页面 Range 写成日历日期,多窗口区块各自改;**最新一天标「暂定」**
7. 更新 Pulled
8. 字段缺失则保留「条件未满足」,不填假数
9. 按 §5.4 核对着色:分档是否与数值一致、**失败少到不可信的是否为灰**、分子恒 0 的段是否显示「不适用」、非健康指标是否误着色
10. 同步改本文件的「状态」列与 [`README.md`](./README.md) 页面表

---

## 8. 落地顺序(按实证可行性重排)

| 顺序 | 任务 | 为什么排这 | 前置 |
| --- | --- | --- | --- |
| ~~1~~ | ~~**#1 登录注册**~~ ✅ 2026-08-07 按 08-06 改稿修订:三段改两段 + ID 同步降为附注;含失败词双取、暂定日标记、停报探测 | — | — |
| 1 | **#3 进入教室健康** | 8,791 条量足;文档 §3.3 口径最完整(含分母分子、reason 枚举、iOS 实测样例) | 无 |
| 2 | **#2 支付订阅健康** | 口径已定稿零开放项;3,129 条偏少但结构清晰 | 无 |
| 3 | **#5 网络 & 三方** | 量最大(合计约 5 万);顺带把 `signature_refresh` / `token_refresh` 从 #1 迁过来 | 无 |
| 4 | **A 总览 + 播报** | 需要 #1 #2 #3 #5 的口径都定稿才能汇总;注意「环比」目前做不到(埋点窗口不足) | 上面三项 |
| 5 | **#8 支付产品漏斗** | 先解决 2,426 条空字段的归属问题 | 查清旧口径 |
| 6 | **#7 新手转化漏斗** | 宽表已就绪,但新旧事件并存需按 §3.2 双取 | 无 |
| 7 | **#4 崩溃 / 性能** | 等 `area='performance'` 量起来;Crashlytics 入 BQ 另说 | 埋点放量 |
| 8 | **#6 A/B** | 先做 SRM 与埋点完整性监控页;发布决策页等分组明细表 | 分组表进 BQ + 读数指南 |
| 9 | **#9 有效学习** | 定义都没有 | 补北极星定义文档 |

需要对外推动的事(不属于看板开发,但决定看板能否做):

| 事项 | 阻塞 | 找谁 |
| --- | --- | --- |
| 服务端 A/B 分组明细表同步到 BigQuery | #6 无法圈样本 | 数据侧 |
| 《转化链路AB实验-读数与统计指南》 | #6 判据未知 | 李双 |
| 「有效学习分钟数」定义 | #9 做不了 | 待定 |
| **iOS 把失败统一改标 `tech_fail`**(见 §3.3) | 所有技术健康看板:只认一个词就静默丢掉整个 iOS,且不报错 | iOS |
| **确认 `app_context_sync_result` 的 `source=login_success / signup_success` 还要不要** | 关键链路正文说「和登录流程不存在联系」,**字段表和示例 JSON 却仍写着这两个值**。实际 Android 0 条、iOS 1,118 条。文档前后不一致,不先澄清就没法判断 Android 是漏埋还是本来就不用埋 | PM / 客户端 |
| **`signup_result` 的 iOS 侧停报** | 最后一条 2026-07-31,Android 仍在报。两端量没有可比性,#1 第 5 节与 #7 漏斗都受影响 | iOS / 服务端 |
| **`signup_method` → `method` 改名只做了一半** | 文档迁移表写「统一为 `method`」,实测只有 `web_h5` 与 `platform` 为空的行改了,双端仍用旧名。取数必须 `COALESCE` 双取 | 双端 / 数据侧 |
| 确认 **Android** 的 `sdk_auth_launch_result` 是否实现「未呈现」三态判定(文档只写了 iOS) | #1 段① 无判别力:1,531 次里只有 1 次失败(iOS 361 次零失败),光「用户取消」就不可能这么少 | Android |
| **用户取消时也上报「已经等了多久」** | 现在耗时只统计成功的登录,放弃的人没进统计 —— 无法验证「因为太慢所以放弃」(Android 每 4.4 人跑掉 1 个,后端换登录态中位耗时 8.79s) | 双端 |
| `result` 表外取值 `skip` / `cancel` 的语义(`push_bind_result` 一万条 `skip`) | 既非成功也非失败,相关看板无法分类 | 客户端 |
| 布尔字段类型双端统一(`is_new_user` / `membership_seeded` / `has_onboarding_payload`) | 取数须双取 string/int,易静默丢一端 | 双端 |
| `auth_entry_source` 补「深链」与「被踢回」两类入口 | #1 无法量化被动登出后的重登健康度 | 双端 |
| 逐条确认 `reason` 未出现枚举的可触发性(authorization 4 个 / backend 5 个) | 埋点未验证,不能证明分支能上报 | 客户端 |
| `is_premium` 未随 `auth_login_result` 上报 | 公共维度「是否会员」缺失 | 客户端 |
| `reason` 文档外枚举 `interrupted` / `unavailable` 的语义 | 归因表口径 | 客户端 |
