Claude
Skills
Sign in
Back

discover-event-surfaces

Included with Lifetime
$97 forever

Given a change_brief YAML (output from diff-intake), generates an exhaustive list of candidate analytics events to instrument. Takes the perspective of an engineer with a PM mindset — surfaces everything worth considering so a PM can decide what actually matters. Use this as step 2 of the analytics instrumentation workflow, immediately after diff-intake produces a change_brief. Trigger whenever a user has a change_brief YAML and wants to know what analytics events to add, or asks "what should I track for this PR", "what events should I instrument", "generate event candidates", or any request to surface analytics coverage gaps for a code change.

Data & Analytics

What this skill does


# discover-event-surfaces

You are step 2 of the analytics instrumentation workflow. Read a `change_brief`
YAML and produce an exhaustive candidate list of analytics events — named well,
organized by category, and ready for PM review.

Think like an engineer who ships the feature AND cares about whether it
succeeds. Generate events that answer product/business questions, not events
that mirror implementation details. Aim for **breadth and quality** — a
downstream skill will narrow the list.

Read the `taxonomy` skill at `../taxonomy/SKILL.md` to understand core
analytics philosophy and naming standards.

---

## 1. Parse the change_brief

- `classification.analytics_scope` — if `none`, stop and tell the user there's nothing to instrument.
- `summary` — one-line description of the change.
- `user_facing_changes` — primary signal. Each entry = something a user can now do or see differently.
- `surfaces.components` — modified UI components; where interactions happen.
- `file_summary_map` — read summaries for files in `surfaces` or touching user-facing logic. Skip tests/config/tooling.

## 2. Scan the codebase and map user flows

Before generating any events, build a concrete understanding of how users move
through the feature. The change_brief gives you file paths and summaries — now
read the actual code to trace the full journey.

### What to read

- Every file listed in `surfaces.components` — read them fully.
- Files from `file_summary_map` that touch user-facing logic (skip tests, config,
  tooling).
- Follow imports and references one level out: if a component calls a hook, API
  function, or navigates to another route, read that target file too. This is how
  you discover steps the diff didn't touch but that are part of the same flow.

### What to look for

Trace the path a user takes from entry to outcome:

- **Entry points** — how does the user arrive? Route definitions, navigation
  calls, menu items, links, feature flag gates.
- **Interaction sequence** — what does the user do step by step? Form fills,
  selections, confirmations, uploads. Look at handler wiring (`onClick`,
  `onSubmit`, `onChange`) and what state they mutate.
- **Async boundaries** — API calls, mutations, server actions. These are where
  "attempted" becomes "succeeded" or "failed."
- **Terminal states** — success confirmations, error handling, redirects,
  completion screens.
- **Branching paths** — conditionals that route users to different outcomes
  (e.g., free vs paid, first-time vs returning).

### Produce a funnel hypothesis

Synthesize what you found into one or more funnels — ordered sequences of user
steps from entry to outcome. Each funnel should have:

- A descriptive name (e.g., "Property extraction flow", "Onboarding wizard")
- The ordered steps, each with the file and function/handler where it happens
- Which step is the **start** and which is the **end**

Not every change has a funnel. Single-action features (a toggle, a one-click
export) don't need one — just note that there's no multi-step flow. But when a
flow exists, mapping it here is what allows you to confidently assign funnel
start/end as critical later.

Keep the hypothesis grounded in code you actually read. Don't invent steps you
didn't see evidence for.

## 3. Determine naming conventions and fetch existing events

Invoke `discover-analytics-patterns` and use its
`event_naming_convention` and `property_naming_convention` outputs. That skill
owns the naming-resolution procedure and precedence order. Do not redefine it
here.

Before generating candidates, pull the project's existing event taxonomy so you can
avoid duplicates and match the naming convention already in use.

### Resolve the project

If the change_brief includes an Amplitude `projectId`, use it directly. Otherwise,
call `get_context` to resolve the project name or ask the user which project to
target. You need a `projectId` for the next call.

### Pull existing events

Call `get_events` with the resolved `projectId` (no cursor needed — just the first
page is enough for pattern detection). This returns event objects with fields like
`eventType`, `category`, `description`, etc.

### Build naming references and an existing event index

1. **Existing event index** — Collect all `eventType` values into a set. You'll
   check candidates against this set in step 4 to avoid proposing events that are
   already tracked. An event is a duplicate if its semantic meaning matches an
   existing `eventType`, not just its exact string — e.g., if `Subscription Upgraded`
   exists, don't propose `Plan Upgraded` for the same action.

## 4. Generate candidate events

Start from the funnel hypothesis. If you identified funnels in step 2, generate
events for the funnel start and end first — these are your anchors. Then fill in
candidates for intermediate steps and non-funnel surfaces.

For each `user_facing_change`, ask: *"If a user does this — what outcomes would a PM want to know about?"*

Generate from four categories (ordered by priority):

| Category             | What it captures                                                                                  | When to include                                      |
| -------------------- | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| **business_outcome** | Revenue, retention, growth actions (purchases, subscription changes, conversion gates)            | Change touches monetization or retention surface     |
| **user_journey**     | Meaningful state transitions (workflow completed, feature activated, onboarding finished)         | Change introduces or alters a user journey step      |
| **feature_success**  | The "it worked" moment — confirmed outcome, not button click (document created, report generated) | Any new or materially changed feature                |
| **friction_failure** | Where users fail, get stuck, or give up (errors, empty states, abandonment)                       | Complex multi-step interactions or error-prone flows |

### Deduplicate against existing events

After generating candidates, check each one against the **existing event index**
you built in step 3. For each candidate:

- **Exact match** — the `eventType` already exists verbatim. Drop the candidate.
- **Semantic match** — a different name tracks the same user action or outcome
  (e.g., you proposed `Plan Upgraded` but `Subscription Upgraded` already exists
  for the same action). Drop the candidate.
- **Partial overlap** — an existing event covers a broader action that subsumes
  your candidate (e.g., `Checkout Completed` already exists and your candidate
  `Payment Submitted` fires at the same moment). Drop unless the candidate captures
  meaningfully different information.

If you drop a candidate because it already exists, note it in a
`already_tracked` list in the output so the user can see what's covered.

## 5. Quality filter

Every candidate must pass all three:

1. **Decision-useful** — A PM could make a product decision from this alone, without five other events for context.
2. **Outcome-focused** — Captures that something *happened*, not that the user *attempted* it. `Property Extracted` > `Extract Button Clicked`. Prefer confirmed outcomes; form submissions are acceptable when no server confirmation exists.
3. **Stable across redesigns** — Named around the business/product concept, not the UI element. If renaming a modal would make the event name stale, it's too coupled.

**Cut:** raw clicks/hovers without outcomes, internal technical actions (API callbacks, state updates), UI-versioned names (`modal_v2_submit`), sub-step-level granularity.

## 6. Name events

Use the naming conventions returned by `discover-analytics-patterns`.
New events should look like they belong with the rest of the instrumentation:
same casing, same word order, same delimiters, same prefix patterns, and the
same level of spec

Related in Data & Analytics