关于 discover-event-surfaces
这是分析埋点工作流中的技能,用于根据 change_brief 为产品经理整理候选分析事件。它强调围绕用户结果构建事件,并结合代码流程、命名规范和已有事件去重。
主要功能
- 01解析 change_brief 与用户界面变更
- 02追踪代码中的用户流程与结果
- 03按分析类别生成候选事件
- 04对照现有事件并去重
- 05制定命名、优先级与埋点位置
适用场景
- 01为新功能整理待评审的事件清单
- 02梳理多步骤功能的漏斗起止事件
- 03检查候选事件是否与现有事件重复
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ amplitude/ mcp-marketplace --skill discover-event-surfaces安装后在 Claude Code 中输入/discover-event-surfaces确认已加载。
详细介绍
discover-event-surfaces
你处于分析埋点工作流的第 2 步。读取 change_brief
YAML,生成一份详尽的候选分析事件清单,命名规范、按类别整理,且可供 PM 审核。
像一位既负责交付功能、又关心功能能否成功的工程师那样思考。生成能回答产品/业务问题的事件,而不是反映实现细节的事件。力求广度和质量——后续技能会缩小清单范围。
阅读 ../taxonomy/SKILL.md 中的 taxonomy 技能,了解核心分析理念和命名规范。
1. 解析 change_brief
classification.analytics_scope——如果值为none,停止并告知用户无需埋点。summary——对变更的一句话描述。user_facing_changes——主要信号。每个条目都代表用户现在可以执行或查看的不同操作。surfaces.components——修改过的 UI 组件;用户交互发生的位置。file_summary_map——读取surfaces中所列文件或涉及面向用户逻辑的文件摘要。跳过测试/配置/工具文件。
2. 扫描代码库并梳理用户流程
生成任何事件前,先具体了解用户如何使用该功能。change_brief 会提供文件路径和摘要——现在请阅读实际代码,追踪完整流程。
要阅读的内容
- 阅读
surfaces.components中列出的每个文件,通读全文。 - 阅读
file_summary_map中涉及面向用户逻辑的文件(跳过测试、配置和工具文件)。 - 向外追踪一层导入和引用:如果某个组件调用了 hook、API 函数,或会导航到其他路由,也要阅读对应目标文件。这样才能发现差异未涉及、但属于同一流程的步骤。
要查找的内容
追踪用户从进入功能到完成操作的路径:
- 入口点——用户如何进入?检查路由定义、导航调用、菜单项、链接和功能标记门控。
- 交互顺序——用户逐步执行哪些操作?例如填写表单、进行选择、确认和上传。查看处理函数的绑定(
onClick、onSubmit、onChange)及其修改的状态。 - 异步边界——API 调用、变更操作、服务端操作。这些环节决定了“已尝试”最终是“成功”还是“失败”。
- 终止状态——成功确认、错误处理、重定向和完成页面。
- 分支路径——将用户引向不同结果的条件判断(例如,免费与付费、首次使用与再次使用)。
提出漏斗假设
根据发现的内容,整理出一个或多个漏斗——按顺序排列从入口到结果的用户步骤。每个漏斗都应包含:
- 描述性名称(例如,“属性提取流程”“入门向导”)
- 按顺序排列的步骤,并注明每一步发生的文件和函数/处理函数
- 明确指出哪一步是起点,哪一步是终点
并非每项变更都有漏斗。单一操作功能(例如开关、一键导出)不需要漏斗——只需说明不存在多步骤流程。但如果确实存在流程,在此梳理流程,才能在之后有把握地将漏斗起点/终点标记为关键事件。
假设必须以你实际阅读过的代码为依据。不要臆造没有证据支持的步骤。
3. 确定命名规范并获取现有事件
调用 discover-analytics-patterns,并使用其输出中的
event_naming_convention 和 property_naming_convention。该技能负责命名规则的解析流程和优先级。不要在此重新定义。
生成候选事件前,先获取项目现有的事件分类体系,以避免重复,并遵循当前使用的命名规范。
确定项目
如果 change_brief 包含 Amplitude projectId,直接使用。否则,调用 get_amplitude_context 来确定项目名称,或询问用户要使用哪个项目。下一次调用需要 projectId。
拉取现有事件
检查已连接的目录,并使用其当前的分类事件读取器以及已解析的 projectId。只能遵循该读取器公布的架构。如果它支持调用方归因,请使用此技能 YAML 前置元数据中的 name 标识此技能。无需游标——第一页足以检测模式。如果其架构支持字段选择,请请求事件名称、类别和描述字段,然后使用返回的字段名称。
构建命名参考并建立现有事件索引
- 现有事件索引 — 将所有
eventType值收集到一个集合中。在第 4 步中,你将使用此集合检查候选事件,避免提出已跟踪的事件。如果某个事件的语义与现有eventType相同,即使名称并不完全一致,也属于重复事件——例如,如果已有Subscription Upgraded,就不要为同一操作提出Plan Upgraded。
4. 生成候选事件
从漏斗假设出发。如果你在第 2 步中识别出了漏斗,先为漏斗起点和终点生成事件——它们是你的锚点。然后补充中间步骤和非漏斗界面的候选事件。
对于每个 user_facing_change,请问:“如果用户执行了这项操作,PM 会想了解哪些结果?”
从四个类别生成候选事件(按优先级排序):
| 类别 | 记录的内容 | 何时纳入 |
|---|---|---|
| business_outcome | 收入、留存、增长相关操作(购买、订阅变更、转化关口) | 变更涉及变现或留存界面 |
| user_journey | 有意义的状态转换(工作流完成、功能激活、引导流程结束) | 变更新增或调整了用户旅程中的步骤 |
| feature_success | “成功了”的时刻——已确认的结果,而非按钮点击(文档已创建、报告已生成) | 任何新增或发生实质性变更的功能 |
| friction_failure | 用户失败、受阻或放弃的地方(错误、空状态、中途退出) | 复杂的多步骤交互或容易出错的流程 |
与现有事件去重
生成候选事件后,将每个候选事件与第 3 步中建立的现有事件索引进行检查。对于每个候选事件:
- 完全匹配 —
eventType已原样存在。移除该候选事件。 - 语义匹配 — 名称不同,但记录的是相同的用户操作或结果(例如,你提出了
Plan Upgraded,但已有Subscription Upgraded记录了相同的操作)。移除该候选事件。 - 部分重叠 — 现有事件涵盖的操作范围更广,包含了你的候选事件(例如,已有
Checkout Completed,而你的候选事件Payment Submitted在同一时刻触发)。移除该候选事件,除非它能记录有意义的不同信息。
如果因某个候选事件已存在而将其移除,请在输出中的 already_tracked 列表里注明,以便用户了解哪些事件已有覆盖。
5. 质量筛选
每个候选事件都必须满足以下三项要求:
- 有助于决策 — 仅凭此事件,PM 就能做出产品决策,无需借助其他五个事件了解背景。
- 关注结果 — 记录某件事已发生,而非用户尝试了某件事。
Property Extracted>Extract Button Clicked。优先选择已确认的结果;如果没有服务器端确认,则可接受表单提交。 - 改版后仍然稳定 — 以业务/产品概念命名,而非以 UI 元素命名。如果重命名某个模态框就会导致事件名称过时,说明耦合过紧。
剔除: 没有结果的原始点击/悬停、内部技术操作(API 回调、状态更新)、包含 UI 版本的名称(modal_v2_submit)、子步骤级的粒度。
6. 为事件命名
使用 discover-analytics-patterns 返回的命名规范。
新事件应与其他埋点保持一致:
使用相同的大小写、词序、分隔符、前缀模式和具体程度。
如果之后需要在理由或埋点提示中建议属性名称,请使用
discover-analytics-patterns 返回的 property_naming_convention。
所有情况下,都应使用产品领域中的主体(Property、User、Document),而非代码名称(PropertyItem、ActionStore)。
| 好(标题式大小写规范) | 差 |
|---|---|
Property Extracted | extract_property_clicked |
Extract Type Configured | type_dropdown_changed |
Property Creation Failed | 500_error_new_property |
7. 确定文件和埋点位置
针对每个候选事件,使用 file_summary_map 和 surfaces.components 来确定:
file— 应放置跟踪调用的源文件。优先选择最接近结果得到确认的位置(而非用户发起操作的位置)。通常是surfaces.components中的组件文件,或异步操作完成时调用的钩子。instrumentation— 用 1-2 句话说明:事件在何时触发(在什么条件/回调/状态转换之后),以及如何接入(应将其放在哪个函数/处理程序中)。引用文件摘要中的实际函数名称,方便工程师找到对应代码行。
8. 深入理解,然后确定优先级
针对每个候选事件,先完成以下两个字段——它们能促使你在评分前具体思考事件的价值:
analysis_recipe— 描述分析师会用此事件构建的具体图表、漏斗或查询。请具体说明可视化类型、细分维度,以及要结合的其他事件。例如:“每周漏斗:Panel Opened → Extract Type Selected → Property Extracted,按 extractType 细分。如果完成率低于 50%,则发出提醒。”stakeholder_narrative— 写一句 PM 可以放进季度回顾或董事会演示文稿的话,用到此事件的数据。假设该指标已经存在,写出它所呈现的故事。例如:“尝试提取的用户中,有 68% 首次尝试就完成了提取,高于上一季度的 45%。” 如果想不出一句有说服力的幻灯片文案,这个事件可能不值得埋点。
现在,结合这些背景,分配一个优先级:
| 优先级 | 含义 | 指引 |
|---|---|---|
| 3(关键) | 如果缺少此事件,你会阻止发布。它回答了团队在第一周一定会提出的问题。 | 仅用于直接衡量功能成功或失败的事件。大多数变更只会产生 1-2 个关键事件。 |
| 2(有用) | 能带来实际分析价值,但即使没有它,功能也可以发布。如果埋点成本较低,值得添加。 | 细分维度、次要工作流、配置选项。 |
| 1(可选) | 有更好,没有也无妨。只有团队有余力且有明确的待验证假设时才埋点。 | 边缘情况故障、探索性参与信号、可发现性指标。 |
漏斗事件值得特别关注。 当变更引入或修改了一个多步骤流程(结账流程、新手引导向导、数据导入流程)时,PM 最先会问:“用户在哪一步流失?”如果漏斗起点和终点之间没有任何可见性,这个盲区就可能掩盖严重的产品问题——如果用户在 5 步中的第 2 步参与度骤降,团队需要了解情况,而不是靠猜测。
漏斗起点和终点事件始终是关键事件(优先级 3)。 没有这两个端点,就无法衡量转化率——这是任何漏斗最重要的指标。无论漏斗有多长或多复杂,这两个事件都不可或缺。
要决定将多少个漏斗中间事件标记为关键事件,请评估漏斗的长度和复杂程度:
- 短流程(2-3 步,单个页面): 起点和终点事件就足够了。简单流程中,不要为每个微小步骤都埋点。
- 中等流程(3-5 步,可能跨多个页面): 在最可能发生流失的位置添加一个中间事件——通常是用户投入精力的环节(填写表单、做出关键选择、上传文件)。
- 长流程(5 步以上,多页面或向导式): 在自然的阶段分界处添加 2-3 个中间事件。考虑跟踪“已开始 → 已配置 → 已提交 → 已确认”,而不是跟踪每次字段交互。
谨慎选择中间事件。你标记为关键事件的每个漏斗事件,都是工程师必须实现、PM 必须监控的一项内容。如果不确定某个中间步骤是否值得跟踪,那它可能就不值得——起点和终点事件会揭示是否存在问题,团队也可以在发现流失严重的位置后再添加更细致的跟踪。
精简为上。聚焦且真正会添加到仪表板中的关键事件,胜过一长串无人查看的事件。如有疑虑,就降低优先级——添加事件比从已有仪表板中移除事件容易得多。
9. 输出 YAML
仅输出 YAML 代码块,不要添加任何外围文字。
event_candidates:
source_summary: "<from change_brief.summary>"
analytics_scope: "<from change_brief.classification.analytics_scope>"
event_naming_convention: "<from MCP if clear, otherwise codebase instrumentation, otherwise taxonomy skill>"
property_naming_convention: "<from MCP if clear, otherwise codebase instrumentation, otherwise taxonomy skill>"
already_tracked: # omit if no duplicates found
- existing_event: "Subscription Upgraded"
candidate_dropped: "Plan Upgraded"
reason: "Same action — existing event already tracks plan/subscription upgrades."
funnels: # omit if no multi-step flows found
- name: "Descriptive funnel name"
steps:
- step: "Step description"
file: "src/components/Foo.tsx"
function: "handleOpen"
role: start # start | intermediate | end
- step: "Next step"
file: "src/components/Bar.tsx"
function: "onSubmit"
role: intermediate
- step: "Final step"
file: "src/hooks/useSave.ts"
function: "onSuccess"
role: end
candidates:
- name: "Event Name Here"
category: feature_success # business_outcome | user_journey | feature_success | friction_failure
rationale: "What PM question this answers."
analysis_recipe: "Weekly trend of completions; funnel from Panel Opened → Extract Type Selected → Event Name, segmented by extract type."
stakeholder_narrative: "Feature X adoption reached 40% of active users within two weeks of launch, exceeding our 25% target."
priority: 3 # 3 = critical, 2 = useful, 1 = optional
funnel: "Funnel name" # which funnel this belongs to, if any
funnel_role: start # start | intermediate | end — omit if not part of a funnel
surface: "ComponentName" # from surfaces.components
file: "src/components/Foo/Bar.tsx"
instrumentation: "Fire after the async save resolves, inside onSuccess of useExtract(). Pass result status."
- name: "Another Event"
category: user_journey
rationale: "..."
analysis_recipe: "..."
stakeholder_narrative: "..."
priority: 2
surface: "..."
file: "..."
instrumentation: "..."
顺序:先列出优先级较高的类别,每个类别内按影响从大到小排序。
示例
输入摘录:
user_facing_changes:
- "Users can now select Extract Type (Text or Attribute) in the PropertyItem panel"
surfaces:
components:
- name: PropertyItem
change: modified
合适的候选项:
- name: "Property Extracted"
category: feature_success
rationale: "Core adoption signal — tells PMs whether the extract workflow completes."
analysis_recipe: "Weekly funnel: Panel Opened → Extract Type Selected → Property Extracted, segmented by extractType. Alert if completion rate drops below 50%."
stakeholder_narrative: "72% of users who open a property panel complete an extraction, up from 0% before this release — validating the new extract workflow."
priority: 3
surface: "PropertyItem"
file: "src/components/PropertiesPanel/PropertyItem.tsx"
instrumentation: "Fire after extract resolves successfully in onSuccess handler. Include extractType (TEXT or ATTRIBUTE)."
- name: "Extract Type Selected"
category: feature_success
rationale: "Shows which mode users prefer — informs investment in Attribute mode."
analysis_recipe: "Pie chart of Text vs Attribute selections over 30 days. Combine with Property Extracted to get per-mode completion rate."
stakeholder_narrative: "85% of extractions use Text mode vs 15% Attribute — we should double down on Text UX before expanding Attribute capabilities."
priority: 2
surface: "PropertyItem"
file: "src/components/PropertiesPanel/PropertyItem.tsx"
instrumentation: "Fire in onChange of Extract Type select, passing new value."
- name: "Property Extraction Failed"
category: friction_failure
rationale: "Surfaces where the extract workflow breaks for reliability prioritization."
analysis_recipe: "Error rate chart: Property Extraction Failed / (Property Extracted + Property Extraction Failed), grouped by error reason. Alert on spikes."
stakeholder_narrative: "Extraction failure rate dropped from 12% to 3% after the v2 error-handling patch — users are hitting fewer dead ends."
priority: 2
surface: "PropertyItem"
file: "src/components/PropertiesPanel/PropertyItem.tsx"
instrumentation: "Fire in catch/onError of extract call. Include error reason if available."
不要包含: Extract Type Dropdown Opened(点击,无结果)、PropertyItem State Updated(内部事件)、Attribute Input Focused(粒度过细)。