Files
patbond-doc/docs/development/iterations/iteration-3/06-experiment-tracking-plan.md
T
lixi d2867826d3
CI / docs-build (push) Successful in 55s
docs: M3 开工分析 8 份报告入档 + ADR-016~021 拍板决策
- iteration-3 报告 01-08(PM 拆解/后端/Flutter/RC 首个 CERTIFIED/UI/埋点/证据基线/Git)
- ADR-016 自托管 MinIO 起步预留迁云(用户确认现无云存储)、ADR-017 patbond-community
  :8084 + media 归 user + 作者信息跨 schema 只读、ADR-018 范围裁剪(话题剪出/单层评论)、
  ADR-019 幂等按域(PUT/DELETE + request_hash)、ADR-020 聚合 feed_viewed/字典 v3/
  北极星不变/队列三项升第一波、ADR-021 Git 修订(main 更正/PR 情形触发/首发布重建 main/
  防泄漏 grep 先行)
- mkdocs 挂「第三迭代」导航,build --strict 通过

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-08 16:02:53 +08:00

39 KiB
Raw Blame History

第三迭代埋点与实验规划(社区)

角色:Experiment Tracker 日期:2026-09-08 前序:iteration-2 06-experiment-tracking-plan.md(字典 v2、北极星定义式、H1~H4、A/B 八项前置)、15-analytics-persistent-queue.md(分段持久化队列实况)、24-event-whitelist-v2.md29-m2-summary.md §4(遗留与 M3 方向)、30-device-verification-checklist.md(真机补验挂起) 依据:development-plan.md 第 4 节 community 域、第 7 节 M3 验收、第 9 节「可观测性与产品验证」;patbond-api EventDictionary.java 现行白名单(v221 事件);patbond-flutter lib/analytics/ 现状(SessionTracker / RouteObserver / 分段队列均已落地) 范围:M3 社区纵切(Feed、帖子、草稿/发布、媒体、评论、点赞、收藏、关注、话题);AI 创作、本地服务不在本轮定义 性质:纯规划文档,供 M3 开发工单直接引用;不含任何代码改动

速览(五个核心结论)

  1. 事件字典 v3 增量 19 个新事件post 域 8 + feed 域 2 + 互动 8 + 实验基建 experiment_exposed 1),命名沿 v1/v2 惯例,结果编码进事件名,见 §1。
  2. Feed 曝光采用「浏览段聚合」设计,逐卡曝光事件被本角色否决——量级重测表明:逐卡设计下 M2 的「零扩容」结论不再成立1,000 DAU 约 7~14 个月击穿 5,000 万行分区阈值,且接收端限流实际未实现、快速滑动会形成无背压直写),聚合设计下零扩容结论继续成立,见 §2。
  3. 新增 4 条可证伪假设 H5~H8(发布渗透率 / 发布漏斗完成率 / 社区-记录协同 / Feed 消费深度),H1~H4 出数日历与责任人落定(判定日 10-06 / 10-13 / 10-20),见 §3。
  4. 北极星建议 M3 保持「7 日回访记录率」不变,社区复合指标不在本迭代引入;复评点设在 M3 收官、以 H7 读数为依据(待拍板),见 §4。
  5. A/B 八项前置的 M3 推进计划:6 项本迭代变绿 + 1 项部分变绿#7 的 feature flag 回滚随社区发布开关顺带落地、监控留 M4),维持「M3 末基本全绿、M4 首实验」路线,见 §5。

0. 基线现状(开工前核对)

M2 收官把 v2 规划的绝大部分落成了现实,本节只记与 M3 规划直接相关的事实。

现状 出处
后端字典 v2 共 21 事件:auth 11 + page_viewed 正稿 + pet 3 + health_record 6health_record_action 已移除(ADR-013 EventDictionary.java 实读
接收端 POST /api/v1/events 批量 150、202 逐条、eventId 幂等、白名单剥离、红线拒绝;64KB 上限与 429 限流均未实现(契约据实未写,09 号 §出入 1/2) 09 号报告
存储 platform.product_events 不分区,分区阈值约 5,000 万行 v1 报告 13 §2.3
客户端会话 session_tracker.dart 已落地(冷启动/30 分钟规则);analytics_route_observer.dart + page_viewed 已挂全 15 号 / 24 号报告
客户端队列 分段持久化(500 条 / 25 段、at-least-once、批 ≤50);冲刷触发点 3/4:满 20 条、退后台、冷启动恢复——30 秒定时器未做 15 号 §2.3/§4
队列遗留三项 30s 定时冲刷、退避/429(依赖后端先有限流)、anonymousId 持久化 29 号 §4 遗留 3
真机补验 Android 落库观察 + SessionTracker 30min 手测挂起(0.5 天清单在 30 号报告)——这是 A/B 前置 #1「数据质量验收」的拦路项 30 号报告
pageName 实况 客户端枚举 13 个:字典 v2 初始 9 个 + 客户端自行补充 4 个(create/pet_archive/services/post_detail),后者尚未同步进字典正稿 analytics_page_name.dart 实读
假设与北极星 H1~H4 判定线已冻结(观察窗自 2026-09-08 起算);北极星 SQL 与 §6 对账 SQL 已入档待巡检 M2 06 号 §2/§3

开工前必须知道的一件事:M2 06 号 §7.1 曾以「限流 60 请求/5 分钟余量十几倍」论证零扩容,但 09 号契约回填核实该限流从未实现——接收端目前对客户端写入没有任何背压。这不改变 M2 量级下的结论(量太小),但 M3 引入首个高频事件后,保护必须内建在事件设计里而不能指望限流兜底,这是 §2 裁定聚合方案的硬前提之一。


1. 事件字典 v3 增量(community 域族)

1.1 沿用原则与域划分

命名 <域>_<动作>_<结果> snake_case、结果编码进事件名(_succeeded/_failed)、单义事件不设结果后缀(沿 health_record_viewed/health_record_deleted 先例)、eventVersion 起始 1、公共属性十项全带、属性 camelCase。v3 新增域前缀:

  • post:帖子生命周期(创建、媒体、草稿、发布、删除)
  • feedFeed 消费(曝光聚合、加载失败)
  • comment:评论
  • user:关注关系(user_followed——关注的对象是用户,域按实体归 user;话题关注见 §1.6 缺口 3)
  • 点赞/收藏归 post 域(作用对象是帖子)

设计纪律沿 v2 §1.2 的教训:不设 community_action(actionType) 式多路复用事件——like/unlike/favorite/unfavorite 是四个语义独立的动作,各自独立成名,任何一个的枚举扩充不污染其他指标口径。

1.2 核心裁定:Feed 曝光用「浏览段聚合」,不做逐卡事件

这是 v3 最重要的一个设计决策,先给结论再给依据(量级数字在 §2 展开):

feed_viewed 定义为「一个 Feed 浏览段」的聚合事件:用户进入 Feed 页起累计计数,离开时(路由跳走 / 退后台)发一条,携带该段的曝光卡片数、翻页数、刷新数与停留时长。卡片「曝光」的客户端判定:卡片可见面积 ≥ 50% 且持续 ≥ 500ms,同一浏览段内按 postId 去重(postId 只在客户端内存里做去重键,绝不上报,上报的只有计数)。

否决逐卡方案(每张卡片可见发一条 post_impression(postId))的四条理由:

  1. 存储击穿(§2.2):逐卡设计使「零扩容」结论失效,M3 就要启动分区改造——为一个当前没有消费方的数据形态提前付基建成本,不成立。
  2. 无背压直写:接收端限流未实现(§0),快速滑动可产生 5–10 卡/秒,客户端满 20 条即冲刷 ≈ 每 2–4 秒一个 HTTP 请求,无任何机制拦截这种放大。
  3. 队列容量反噬:500 条队列按 M2 量级可容两周离线积压,逐卡设计下缩水到 2~4 天,离线场景开始真实丢数据(丢最旧整段),反而伤害其他低频高价值事件。
  4. 当前无消费方:逐卡曝光的唯一刚需是「按帖子算曝光-点击率」供推荐排序实验用。M3 的 Feed 是游标分页的时序流、没有排序算法;等 M4+ 真做排序实验时,逐帖曝光的正确采集点是服务端 Feed 下发日志server-side,天然全量、无客户端丢失率问题),而不是客户端埋点。此路线记入 backlog(§8 拍板 6),届时按需再评估分区与采样。

聚合方案的代价是丢失「单帖曝光→点进」归因,保留的是本迭代真正要回答的问题:人们刷不刷、刷多深、刷完动不动手(H8、H5 的数据源)——按需采集,不为想象中的分析囤数据。

1.3 隐私红线增量(社区内容是重灾区,在 v2 五条之上追加)

社区域的埋点只记行为不记内容,且社区首次引入「用户生成内容 + 用户间关系」,红线从严:

  1. 帖子/评论正文:任何自由文本禁止上报;文本规模用 textLengthBucket 枚举(empty / short(≤50) / medium(51500) / long(>500)),不报精确字数。
  2. 内容 ID 与用户 IDpostId、commentId、topicId、被关注/被赞用户的 userId 一律不进 props(公共属性里的 userId 是行为主体自己,这是既有契约;行为客体的任何标识不上报)。逐卡曝光被否决后,v3 全部事件无一需要内容 ID。
  3. 话题名:话题是公开分类词但仍不上报名称(自建话题可能含用户自由文本),只报 topicCount;话题维度的内容分析走服务端事实表。
  4. 媒体线索:文件名、本地路径、URL 禁止;只允许 mediaType 枚举与 sizeBucket 枚举(lt_1mb / mb_1_5 / mb_5_20 / gte_20mb),不报精确字节数。
  5. pageName 归一化(红线 5 延伸):post_detailtopic_detailuser_profile 等带参数路由,参数一律剥离,UUID 出现在 pageName/referrer 即验收失败。

红线正则本轮仍不扩(理由同 v2 §1.3);值级巡检(v2 §6.4 长度 >64 扫描)天然覆盖「正文塞进合法字段」的泄漏形态,继续每日跑。

1.4 新事件清单

失败枚举基底(v2 七项之上按 M3 验收新增):

  • content_rejected — 内容审核/敏感词拒绝(待拍板M3 是否有审核环节,无则删)
  • media_too_large / unsupported_format — 媒体上传专用
  • not_found 复用 — 目标帖子/评论已被删除(对应验收「删除内容不可继续出现」的客户端时序窗口)

发布漏斗(post 域)

事件名 触发时机 专有属性
post_create_started 进入发帖编辑器并产生首次输入(含首次选媒体),每次进入记一次 entryPointcreate_tab / feed / topic_detail / pet_detail,待 UI 定稿收敛)
post_draft_saved 草稿保存成功响应后;仅手动保存与离开时保存,若产品做打字自动保存,自动保存不埋(防高频) triggermanual / on_exit)、mediaCount
post_publish_succeeded 发布接口成功响应后(漏斗事件H5/H6 核心数据源) durationMsstarted→publish)、mediaCounttopicCounttextLengthBucketfromDraftbool
post_publish_failed 发布失败 / 超时 / 本地校验拦截 failureReasonerrorCodehttpStatusattemptSeq
post_deleted 删帖成功响应后(单事件风格,失败靠服务端错误率观测) 无专有属性

post_publish_failed.failureReasonvalidation_errorcontent_rejected(待拍板)、media_upload_incomplete(有媒体未传完即点发布)、rate_limitednetwork_errorserver_error

媒体上传漏斗(post 域,逐文件)

事件名 触发时机 专有属性
post_media_upload_started 单个媒体文件开始上传 mediaTypeimage / video)、sizeBucket
post_media_upload_succeeded 单文件上传成功 mediaTypesizeBucketdurationMs
post_media_upload_failed 单文件失败 / 超时 / 用户取消 mediaTypesizeBucketfailureReasonerrorCodehttpStatusattemptSeq

逐文件(而非逐帖聚合)的理由:上传是发布漏斗预判的最大流失段(H6),失败归因需要文件粒度的 sizeBucket × mediaType × failureReason 交叉;量级无忧——单帖媒体数有产品上限(九宫格类,≤9),非高频。failureReasonmedia_too_largeunsupported_formatnetwork_errorserver_errorcancelled

Feed 消费(feed 域)

事件名 触发时机 专有属性
feed_viewed 离开 Feed(路由跳走 / 退后台)时发一条,聚合本浏览段(§1.2 裁定) feedTabhome / topic / user_posts / favorites,待 UI 定稿收敛)、durationMsimpressionCount(≥50% 可见 ≥500ms、段内按帖去重)、loadMoreCount(翻页次数)、refreshCount(下拉刷新次数)
feed_load_failed 刷新或翻页请求失败(M3 验收「分页不丢失不重复」的客户端观测点) feedTabloadTyperefresh / load_more)、failureReasonerrorCodehttpStatus

实现注意:impressionCount 去重集合只存活于浏览段内存中,段结束即弃;durationMs 用前台时长(退后台暂停计时),上限截断 30 分钟(防止挂机污染 H8)。

帖子详情浏览不设 post_viewed——由 page_viewed(pageName=post_detail) 覆盖(沿 v2 pet_viewed 不设的同一先例,防双事件重复计数)。

互动(post / comment / user 域)

事件名 触发时机 专有属性
post_liked 点赞成功响应后 sourcefeed / post_detail
post_unliked 取消点赞成功响应后 source
post_favorited 收藏成功响应后 source
post_unfavorited 取消收藏成功响应后 source
comment_create_succeeded 评论提交成功响应后 durationMsisReplybool,楼中楼)、textLengthBucket
comment_create_failed 评论提交失败 failureReasonerrorCodehttpStatusattemptSeq
user_followed 关注成功响应后 sourcepost_detail / feed / user_profile / follow_list
user_unfollowed 取关成功响应后 source

取舍说明(与 v2 同款自觉取舍,复活条件注明):

  • 点赞/收藏/关注不埋失败:幂等写入、单点交互,失败率靠服务端接口错误率观测(health_record_deleted 先例)。若乐观更新回滚率成为问题,届时以 eventVersion=2 增补 _failed
  • 评论不设 comment_create_started:短表单,沿 v2「编辑不设 started」先例;评论放弃率若成为问题再增补。
  • like/unlike 分立而非 action 属性v2 §1.2 废弃 health_record_action 的同一逻辑——H5 的「互动用户」分母定义只引用语义单一的事件名。

实验基建(platform 域,A/B 前置 #5 提前进字典)

事件名 触发时机 专有属性
experiment_exposed 用户实际到达实验触点时(渲染了变体 UI),非分配时 experimentKey(实验注册表枚举)、variant

M4 首实验才启用,但字典与白名单本迭代一次进M3 后端反正要动 EventDictionary,避免 M4 为一个事件再开一轮字典工单;客户端强类型封装同批出(可先无调用方)。这直接把 A/B 前置 #5 在 M3 变绿(§5)。

1.5 v3 增量总览(19 个新事件)

# 事件名 版本 性质
22 post_create_started 1 新增
23 post_draft_saved 1 新增
24 post_publish_succeeded 1 新增(漏斗事件)
25 post_publish_failed 1 新增
26 post_deleted 1 新增
27 post_media_upload_started 1 新增
28 post_media_upload_succeeded 1 新增(漏斗事件)
29 post_media_upload_failed 1 新增
30 feed_viewed 1 新增(聚合曝光,首个高频事件)
31 feed_load_failed 1 新增
32 post_liked 1 新增
33 post_unliked 1 新增
34 post_favorited 1 新增
35 post_unfavorited 1 新增
36 comment_create_succeeded 1 新增
37 comment_create_failed 1 新增
38 user_followed 1 新增
39 user_unfollowed 1 新增
40 experiment_exposed 1 新增(M4 启用,字典先行)

后端 EventDictionary 白名单增量(工单可直接抄):

// v3 增量 post 域(iteration-3 报告 06 §1.4
Map.entry("post_create_started", Set.of("entryPoint")),
Map.entry("post_draft_saved", Set.of("trigger", "mediaCount")),
Map.entry("post_publish_succeeded",
        Set.of("durationMs", "mediaCount", "topicCount", "textLengthBucket", "fromDraft")),
Map.entry("post_publish_failed",
        Set.of("failureReason", "errorCode", "httpStatus", "attemptSeq")),
Map.entry("post_deleted", Set.of()),
Map.entry("post_media_upload_started", Set.of("mediaType", "sizeBucket")),
Map.entry("post_media_upload_succeeded", Set.of("mediaType", "sizeBucket", "durationMs")),
Map.entry("post_media_upload_failed",
        Set.of("mediaType", "sizeBucket", "failureReason", "errorCode", "httpStatus", "attemptSeq")),
// v3 增量 feed 域(聚合曝光设计,§1.2 裁定)
Map.entry("feed_viewed",
        Set.of("feedTab", "durationMs", "impressionCount", "loadMoreCount", "refreshCount")),
Map.entry("feed_load_failed",
        Set.of("feedTab", "loadType", "failureReason", "errorCode", "httpStatus")),
// v3 增量互动
Map.entry("post_liked", Set.of("source")),
Map.entry("post_unliked", Set.of("source")),
Map.entry("post_favorited", Set.of("source")),
Map.entry("post_unfavorited", Set.of("source")),
Map.entry("comment_create_succeeded", Set.of("durationMs", "isReply", "textLengthBucket")),
Map.entry("comment_create_failed",
        Set.of("failureReason", "errorCode", "httpStatus", "attemptSeq")),
Map.entry("user_followed", Set.of("source")),
Map.entry("user_unfollowed", Set.of("source")),
// A/B 前置 #5:曝光事件字典先行,M4 启用(§1.4)
Map.entry("experiment_exposed", Set.of("experimentKey", "variant"))

Flutter 侧沿用强类型封装惯例:新建 post_analytics.dart / feed_analytics.dart / community_interaction_analytics.dart,枚举编译期锁死。

1.6 漏斗闭环与维度够用性复核

复核方法同 v2 §1.6:以 §3 假设与 M3 验收逐条反推数据源。

闭环成立:发布漏斗四段 page_viewed(post_form) → post_create_started → post_publish_succeeded/failed(媒体上传子漏斗嵌套其中,started→succeeded/failed 配对完整);Feed 消费闭环 feed_viewed(曝光量)→ page_viewed(post_detail)(点进)→ 互动事件。发布漏斗的「到达→动笔」段由 pageName 新增 post_form 承接(§6),与 v2 修订 1 的 pet_form 同构——这次在设计期就补上,不留缺口。

缺口 1(接受不埋):逐帖曝光-点击归因——§1.2 已论证,M4+ 走服务端日志路线,backlog 登记。

缺口 2(接受不埋):评论/帖子的浏览深度(评论区滚动)——page_viewed(post_detail) 足够回答「点进率」,评论区消费深度在排序实验之前无消费方。

缺口 3(待拍板):话题关注——若 M3 UI 有「关注话题」按钮,需增补 topic_followed/unfollowed(source)(不报话题名,红线 3);UI 定稿前挂起(§8 拍板 5)。

维度够用性:H5 需互动/发布事件按 userId 去重(有);H6 需发布漏斗配对 + 媒体子漏斗(有);H7 需互动事件与 health_record_create_succeeded 的 userId + serverTs(有,跨域 join);H8 需 feed_viewed.impressionCount/loadMoreCount(有)。全部假设可由 v3 字典 + community 事实表回答,判定通过。


2. Feed 曝光量级评估与「零扩容」结论复核

2.1 v3 上线后的单用户日事件量重估

来源 条/DAU/日 说明
M2 存量(auth + page_viewed + pet/health_record 1530 v2 §7.1 估算,实测待巡检校准
page_viewed 社区页面增量 +510 post_detail 点进是主要来源
feed_viewed(聚合) +38 每浏览段一条
互动(like/favorite/comment/follow 及 un-* +310 活跃互动者
发布漏斗 + 媒体 + 草稿 +0.53 发布是低频动作(H5 预估 ≤10% 用户/周)
合计 2761 约 M2 的 2 倍

2.2 「零扩容」结论复核:聚合设计下成立,逐卡设计下不成立

聚合设计(本方案)

  • 接收端:61 条/日、满 20 条冲刷 ≈ 3–4 请求/日/用户,即便未来补 60 请求/5 分钟限流也有百倍余量。契约、批上限 50、接收逻辑均不动
  • 存储:1,000 DAU × 60 条 × 365 天 ≈ 2,200 万行/年,距 5,000 万分区阈值仍有约 2 年余量。不分区决策继续有效。
  • 队列:500 条 ≈ 8 天以上离线积压(vs M2 两周,可接受),上限不调
  • 结论:零改动,「零扩容」结论继续成立。

逐卡设计(被否决方案,留数字供复议)

  • 活跃刷 Feed 用户 2–4 段/日 × 2060 卡 ≈ 40–240 条曝光/日,总量升至 100250 条/DAU/日。
  • 存储:1,000 DAU 中位 ≈ 4,400 万行/年、上沿 ≈ 9,100 万行/年——7~14 个月击穿分区阈值,M3 就得启动分区 + 保留策略改造。
  • 突发:快速滑动 5–10 卡/秒 → 每 2–4 秒满 20 条冲刷一次 → 单用户可达 75–150 请求/5 分钟;限流未实现(§0),这是对接收端和数据库的无背压直写。
  • 队列:500 条仅容 2–4 天离线积压,挤压其他事件的 at-least-once 保障。
  • 结论:逐卡设计使 M2「零扩容」结论失效——这就是 §1.2 裁定的量化依据。

2.3 队列遗留三项的 M3 处置(优先级重排)

遗留项(29 号 §4 M3 处置 理由
30s 定时冲刷 本迭代第一波做P1 社区场景出现「长前台会话」(刷 Feed 半小时不切页),现有三触发点在这种会话里最多积压 19 条不上传;定时器同时改善当日监控的数据新鲜度。实现按 15 号 §4 既定方案。
退避 + 429 处理 客户端退避本迭代做(5xx/网络错误指数退避 + 抖动);429 分支随后端限流落地一并做 后端限流是 09 号出入 5 项排期评估的一部分(后端侧决策);客户端 5xx 退避不依赖它,社区量级翻倍后重试风暴的伤害面变大,先行。
anonymousId 持久化 本迭代做P2,一行级改动) 现状每次冷启动新生成(analytics_service.dart 构造器 Uuid().v4()),登录前事件无法跨启动归并。A/B 前置 #4 的「登录前实验 anonymousId 分流」硬依赖持久化——M3 不做,M4 首实验若涉及注册/登录前触点就被卡住。

以上三项均为 lib/analytics/ 内改动,与社区功能开发无耦合,建议与字典 v3 后端工单同批排入第一波。


3. 产品假设:H5H8 新增 + H1H4 出数日历

3.0 方法约定(沿 v2 §3,两点强调)

判定线上线前登记并 PM 会签冻结,届满出「支持 / 证伪 / 数据不足」三态判定。H5~H8 的观察窗自社区功能对用户可用之日(下称 T0,随 M3 发布日落定)起算,T0 后第 1 周为尝鲜噪声期,除 H6 外剔除。社区上线会扰动 M2 假设的在途窗口,处理纪律见 §3.2。

H5:社区消费者远多于生产者,但生产者渗透率决定内容池成活(发布渗透假设)

  • 陈述:稳定期内,周活跃用户中当周产生 ≥1 条 post_publish_succeeded 的比例 ≥ 5%。
  • 判定指标:周去重 userId(post_publish_succeeded) / 周去重 userId(任意事件);辅助读数:互动渗透率(≥1 条 like/favorite/comment/follow 的占比)。
  • 判定线:支持 = ≥ 5%;证伪 = 连续 3 周 < 2%;25% 顺延。
  • 窗口T0 后第 25 周。
  • 行动:证伪 → 发布门槛过高或动机不足,「从健康记录一键生成帖子」类降门槛引导进 A/B 候选池;不在 Feed 排序上浪费资源(内容池不成活时排序无意义)。支持 → 内容池自生长成立,资源投向消费侧(H8)。

H6:媒体上传是发布漏斗的最大流失段(漏斗诊断假设)

  • 陈述:发布漏斗完成率(post_publish_succeeded / post_create_started,24h 归因窗)≥ 60%,且流失集中在含媒体的发布(含媒体发布的完成率比纯文字低 ≥ 15pp)。
  • 判定指标:漏斗配对 + post_media_upload_failedsizeBucket × failureReason 分布交叉定位。
  • 判定线:支持 = 完成率 ≥ 60% 且媒体差 ≥ 15pp;证伪 = 完成率 < 40%(漏斗整体坏,另找原因)或媒体差 < 5pp(流失不在媒体段);其余顺延。
  • 窗口T0 后第 14 周(含噪声周——漏斗诊断恰恰要看首批用户的失败形态,沿 H4 先例)。
  • 行动:支持 → 上传压缩/断点续传优化排 M4 前置;证伪且完成率低 → 按 failureReason 分布重新归因(validation_error 高则查表单/文案)。

H7:社区活跃提升记录回访(社区-记录协同假设,北极星拍板的数据依据)

  • 陈述:首记后 7 日内产生过 ≥1 次社区互动(like/favorite/comment/follow/publish 任一成功事件)的用户,其 7 日回访记录率比无互动者高 ≥ 8pp。
  • 判定指标:北极星 SQL(M2 06 号 §2.1)按「窗口内是否有社区互动事件」分两群比较;回访事件仍只算 health_record_create_succeeded(社区行为只做分群、不充当回访,无循环)。
  • 判定线:支持 = 差值 ≥ 8pp 且两群各 ≥ 100 人;证伪 = 差值 < 3pp 或倒挂;38pp 顺延。
  • 窗口:T0 后 6 周(需 ≥ 2 个成熟队列)。
  • 方法论警示:观察性对照,只证相关(活跃用户本来什么都多做,自选择偏差与 H3 同款)。支持的正确用法是把「记录完成页引导分享到社区」列为 A/B 候选,用随机化坐实;同时它是 §4 北极星复评的核心输入——若证伪(社区与记录是两个不相干场景),复合北极星的动议应就地终结
  • 行动:支持 → A/B 候选池 + 北极星复评启动;证伪 → 社区按独立场景运营,北极星保持记录型不再复议。

H8:Feed 首屏之外仍有消费需求(内容供给/消费深度假设)

  • 陈述:稳定期内,≥ 40% 的 Feed 浏览段发生翻页(feed_viewed.loadMoreCount ≥ 1)。
  • 判定指标:翻页浏览段占比;辅助读数:浏览段 impressionCount 中位数、durationMs 分布(截断 30min,§1.4)。
  • 判定线:支持 = ≥ 40%;证伪 = 连续 3 周 < 20%2040% 顺延。
  • 窗口T0 后第 25 周。
  • 行动:证伪 → 首屏即耗尽兴趣,指向内容供给不足(结合 H5 判定:若 H5 也证伪则是供给问题,运营/官方内容或 M4 AI 创作「一键发帖」提前;若 H5 支持则是分发问题);支持 → 游标分页体验(预加载、去重)投入合理,排序实验(M4+)有消费基础。

3.2 H1~H4 与北极星在 M3 期间的出数安排

M2 冻结的窗口自 2026-09-08 起算,判定日历与责任人如下(周节奏:每周一数据侧跑 M2 06 号 §6 全部对账 SQL + §2.1 北极星 SQL,本角色复核读数并记入巡检记录):

窗口 关键日期 跑数责任 判定责任
北极星首个成熟周队列 W37 队列(09-07~09-13 首记)+8 天成熟 2026-09-21(周一)首次出数,此后每周一滚动 数据侧 本角色发布(Wilson 95% CI<50 人周合并)
H4 激活链路 上线后 4 周(含第 1 周) 2026-10-06 判定 数据侧 本角色 + PM 会签
H2 多宠 上线后 4 周末读数 2026-10-06 判定pet.pets 真值侧) 数据侧 同上
H1 记录类型分布 第 25 周(09-15~10-12 2026-10-13 判定 数据侧(§6.2 SQL 即读数) 同上
H3 提醒-回访 6 周(≥2 成熟队列) 2026-10-20 判定 数据侧 同上

社区上线对在途窗口的污染纪律:若 T0(社区发布日)落在 H1/H3 窗口内,判定线不改(冻结纪律),但读数发布时必须按 T0 前/后拆周标注;H3 若前后两段方向不一致,判定记「数据不足-顺延」并注明混杂因素,不得挑一段下结论。H7 的对照组恰好提供了交叉检验。

前置风险:H1~H4 与北极星的一切读数都以真实事件流入库为前提。真机补验(30 号清单)未完成前,Android 端数据可信度未验证——补验必须在 09-21 首次北极星出数前完成,否则首批读数只能标「未验收数据,仅供方向参考」。


4. 北极星:M3 保持「7 日回访记录率」,不引入社区复合指标(待拍板)

社区上线后「北极星要不要变」是必答题。本角色立场:M3 全程保持现北极星不变,理由三条:

  1. 基线刚建立,换指标即断线。北极星 09-21 才出第一个成熟队列读数,M3 期间总共只会积累 4~6 个可比周。此时切换或掺入社区成分,等于永远失去「社区上线前后」这组最有价值的对照——北极星的首要职责是跨迭代可比。
  2. 新功能光环效应会系统性高估社区成分。任何复合指标(如「7 日回访有效行为率 = 记录或发帖或互动」)在社区上线后前几周必然被尝鲜流量冲高,读数好看但不可解释,恰好违背 v2 选 A 弃 B 的原始理由(拒绝易被一次性行为冲高的指标)。
  3. 「社区是否服务于留存」本身是待验假设,不是前提。这正是 H7 的问题。把社区写进北极星等于未经验证就宣布答案。正确顺序:H7 出数(T0+6 周)→ 若支持且 A/B 坐实,M4 起再评估复合式(候选形态:分子扩为「记录 或 发布」,互动类行为因信号太弱不入分子);若 H7 证伪,动议终结。

落定为拍板项(§8 拍板 1):M3 保持不变,复评点 = M3 收官会 + H7 读数;PM 保留否决权,否决须给出替代定义式与断线代价的处置方案。社区侧的健康度用辅助指标层观测(不升格):周发布渗透率(H5 口径)、周互动渗透率、Feed 翻页率(H8 口径)——三者随 §7 巡检周报发布。


5. A/B 八项前置的 M3 推进计划

M2 06 号 §4.2 立的路线是「M3 末全绿、M4 首实验」。逐项落定 M3 的动作与责任侧:

# 前置条件 M3 动作 责任侧 M3 末预期
1 数据质量验收 真机补验(30 号清单,0.5 天)→ M2 字典 v2 事件 2 周巡检达标(丢失 <5%、对账偏差 <5%、去重 <10%、serverTs 100%、无红线泄漏) 数据 + 真机执行人 绿(拦路项是真机,见 §3.2 风险)
2 指标基线 北极星 + M2 漏斗连续 ≥2 周稳定产出(09-21 起自然达成),留档均值与方差 数据 绿
3 样本量规则成文 基线率 × MDE × α=0.05 × 功效 80% 的计算方法 + 查表 + 按实测 DAU 换算最短运行时长;以 §3 实测基线代入(不再用 M2 的假设值) 本角色 绿M3 中交付)
4 稳定分流组件 hash(userId, experimentSalt) % buckets 后端组件 + anonymousId 持久化(§2.3,登录前分流的前提)+ 登录后归并规则成文 后端(归并规则:本角色) 绿
5 曝光事件 experiment_exposed 已随 v3 进字典(§1.4);Flutter 强类型封装同批出 后端 + Flutter 绿(本报告已完成设计)
6 实验设计模板与评审流程 模板(假设/主指标/护栏/提前停止规则/多重比较约定)+ 评审流程成文;与 #3 同一文档交付 本角色 绿
7 护栏监控与回滚 feature flag 开关机制随「社区功能发布开关」顺带落地(社区本就该有开关灰度);护栏准实时监控留 M4(依赖监控设施选型) 后端/DevOps 部分绿(回滚绿、监控 M4
8 隐私合规复核 每实验一次,常态项 每实验 常态

结论:M3 末 6 项全绿 + #7 部分绿,M4 初补齐监控即可启动首实验。 首实验候选池按判定结果动态排序:H3 支持 →「默认引导创建提醒」;H4 证伪 →「建宠成功页引导首条记录」;H7 支持 →「记录完成页引导分享社区」;H5 证伪 →「记录一键生成帖子」。届时按 #3 的样本量规则做可行性检验(运行 >8 周即判不可行,退回观察,止损线预登记——沿 M2 §4.3 纪律)。


6. pageName 枚举增量与 page_viewed 覆盖检查

6.1 增量清单

现状(§0):字典正稿 9 个 + 客户端已自行补充 4 个未同步正稿。v3 一次收编 + 社区族增量:

pageName 性质 说明
create / pet_archive / services / post_detail 收编转正(客户端已存在) 补进字典说明,消除枚举双源
post_form 新增 发帖编辑器——发布漏斗「到达段」承接者(§1.6),对应 v2 的 pet_form 教训,设计期即补
topic_list 新增 话题列表/广场
topic_detail 新增 话题详情(含话题内 Feed;话题 ID 剥离)
user_profile 新增 他人主页(自己的主页仍是 profile,两者语义不同不合并;用户 ID 剥离)
follower_list / following_list 新增 粉丝/关注列表分立(关注关系的两个方向是不同页面)
favorite_list 新增 我的收藏
draft_list 新增 草稿箱

9 个新增 + 4 个收编。Feed 本体不新增 pageName:首页 Tab 即 Feed,沿用 homepageName 保持导航语义,Feed 消费的度量职责已由 feed_viewed 承担,避免一次改名断掉 M2 以来的 home 时序)。终稿在社区 UI 定稿后由 UI + 本角色对齐一次(§8 拍板 4)。

后端零改动提示:page_viewed 白名单只校验 props pageName/referrer),值级枚举由客户端编译期锁死 + 离线巡检兜底——pageName 增量不需要动 EventDictionary,只改 analytics_page_name.dart 与字典文档。

6.2 覆盖检查(社区页面族接线的验收 sanity)

沿 v2 §5.2/§6.3.2 框架,社区族新增三条关系式(数据侧入每日巡检):

  1. 互动必有承载页:产生过互动事件(like/favorite/comment/follow)的 session 必有 ≥1 条 page_viewedpageName ∈ {home, post_detail, topic_detail, user_profile})。偏差 >5% = 社区页面路由漏挂。
  2. 曝光先于点进:日 feed_viewed.impressionCount 总和 ≥ 日 page_viewed(pageName=post_detail) 条数(点进的帖子必先曝光;深链/推送入口出现前该式恒成立,破式即 feed_viewed 聚合逻辑漏计)。
  3. 发布必经编辑器:日 post_publish_succeeded + post_publish_failed ≤ 日 page_viewed(pageName=post_form)(发布尝试必先到达编辑器)。

7. 对账 SQL v3 增量(真值:community 事实表)

v1/v2 巡检全部继续。表名以 M3 后端 DDL 定稿为准,下文假定 community schemacommunity.postscommunity.commentscommunity.post_likescommunity.post_favoritescommunity.follows),命名不同替换即可。

7.1 发布对账(H5 真值侧)

post_publish_succeeded 事件数 vs community.posts 当日新建行数(排除草稿态),UTC 日界,偏差 >5% 告警——结构同 v2 §6.1,替换事件名与表名即可,不重抄。评论对账同构(comment_create_succeeded vs community.comments)。

7.2 互动净值对账(点赞/收藏的 toggle 语义专用)

like/unlike 是幂等 toggle,事实表存的是净状态,逐日计数对账不成立,改对净增量

-- 日 (post_liked - post_unliked) 事件净值 vs community.post_likes 当日净增行数
WITH evt AS (
    SELECT date_trunc('day', server_ts AT TIME ZONE 'UTC') AS day,
           count(*) FILTER (WHERE event_name = 'post_liked')
         - count(*) FILTER (WHERE event_name = 'post_unliked') AS evt_net
    FROM platform.product_events
    WHERE event_name IN ('post_liked', 'post_unliked')
    GROUP BY 1
)
SELECT e.day, e.evt_net, a.api_net,
       abs(e.evt_net - a.api_net) AS diff_abs   -- 相对偏差对净值无意义,看绝对差趋势
FROM evt e
JOIN (SELECT date_trunc('day', created_at AT TIME ZONE 'UTC') AS day,
             count(*) AS api_net          -- 若删行实现取消,需改为审计表/净增视图,DDL 定稿后校准
      FROM community.post_likes GROUP BY 1) a USING (day)
ORDER BY e.day;

(若后端用删行实现取消点赞,api_net 须改从审计日志或快照差分取数——DDL 定稿后由数据侧校准,此处登记口径意图。收藏、关注同构。)

7.3 feed_viewed 自洽巡检(聚合事件的质量门)

聚合事件一旦逻辑有 bug,坏的是整段计数,须专设 sanity:

SELECT date_trunc('day', server_ts AT TIME ZONE 'UTC') AS day,
       count(*)                                                        AS segments,
       count(*) FILTER (WHERE (props->>'impressionCount')::int = 0
                          AND (props->>'durationMs')::int > 10000)     AS zero_imp_long_stay,
       -- 停留超 10s 却零曝光 = 曝光判定逻辑失效,>1% 告警
       count(*) FILTER (WHERE (props->>'durationMs')::int > 1800000)   AS over_cap
       -- durationMs 超 30min 截断上限 = 计时暂停逻辑失效,期望恒 0
FROM platform.product_events
WHERE event_name = 'feed_viewed'
GROUP BY 1 ORDER BY 1;

7.4 巡检节奏汇总

  • 每日v1/v2 既有全部 + §7.1~7.3 + 值级泄漏扫描(v2 §6.4,社区正文是新的高风险源)。
  • 每周一:北极星 + H 假设读数(§3.2 日历);辅助指标层三项(§4)随周报发布。

8. 待拍板清单(汇总)

# 事项 选项 本角色裁定/建议
1 北极星是否随社区调整 保持 7 日回访记录率 / 引入社区复合指标 建议保持,复评点 = M3 收官 + H7 读数(论证 §4);PM 否决须给替代定义式与断线处置
2 H5~H8 判定线 §3 各阈值 T0 前 PM 会签一次,会签后冻结(同 H1~H4 纪律)
3 content_rejected 枚举 M3 是否有内容审核环节 有则保留,无则从枚举删(发布/评论两处)
4 entryPoint/feedTab/pageName 终稿 待社区 UI 定稿收敛 埋点工单开工前 UI + 本角色对齐一次(含拍板 5)
5 话题关注事件 UI 有「关注话题」则增补 topic_followed/unfollowed 按 UI 定稿定(§1.6 缺口 3
6 逐帖曝光路线 本迭代不做(§1.2 裁定);M4+ 排序实验若立项,走服务端 Feed 下发日志 backlog 登记,届时同评分区与采样
7 后端限流排期 09 号出入 5 项之一 建议 M3 排入(客户端 429 分支在等它,§2.3);非本角色职权,仅登记依赖
8 真机补验时限 30 号清单 0.5 天 建议 09-21 前完成(北极星首次出数的数据可信前提,§3.2 风险)

附:M3 埋点工单拆分建议(按依赖排序)

  1. 真机补验(30 号清单,独立于开发,越早越好——拍板 8)。
  2. Flutter 队列三小修(§2.330s 定时器、5xx 退避、anonymousId 持久化)——lib/analytics/ 内闭环,先于社区新事件。
  3. 后端EventDictionary v3 增量 19 事件(§1.5 代码块可直抄,含 experiment_exposed+ 集成测试;可与 2 并行。
  4. FlutterpageName 增量与收编(§6.1analytics_page_name.dart+ 社区页面族路由挂接。
  5. Flutter:社区功能开发时按 §1.4 挂接(强类型封装先行;feed_viewed 的浏览段聚合器建议独立类 + 单测覆盖曝光判定/去重/计时暂停/30min 截断)。
  6. 数据:§7 对账 SQL 入巡检(7.2 口径待 DDL 定稿校准);§6.2 三条覆盖 sanity 随社区页面上线启用。
  7. 后端:分流组件 + 归并规则(A/B 前置 #4,§5)。
  8. 本角色:H5~H8 判定线 T0 前会签冻结(拍板 2);样本量规则 + 实验设计模板文档(前置 #3/#6)M3 中交付;每周一北极星/假设读数复核(§3.2 日历)。