# Emitter search: before anything is called unused

An inventory shows what a tool kept, not what code sent. Search every emitter root before calling an event "not emitted", "unused" or a candidate for retirement. Until then the finding says "not observed in <tool>".

## Contents

- Why "not observed" is not "not emitted"
- Roots to search
- Search patterns
- Dynamic names and gating
- What to record per event
- Labels and what they allow

## Why "not observed" is not "not emitted"

- Consent: a denied state can keep a tool from receiving an event that the code still sends to others.
- CDP routing: destination filters, mappings and disabled destinations in Segment or RudderStack.
- Schema enforcement: Amplitude's reject setting, Segment Protocols blocking, RudderStack drop settings.
- GA4 event rules: a modification can rename the event before it is stored; a created event can produce a name no code sends.
- Ad blockers and network loss on browser routes.
- Reports that withhold or group low-volume rows.
- A code path users rarely reach inside the window, or an inventory that was capped or partial.

## Roots to search

- Web, mobile, backend and job repositories, including shared tracking wrappers and generated clients.
- GTM web and server containers (the export JSON; gtm-container-audit reads it).
- CDP sources, functions, destination filters and mappings.
- Tool-side rules: GA4 created and modified events (Admin > Data display > Events); Amplitude transformations (`get_transformations` reads them); Mixpanel merges and custom events; PostHog transformations.
- Warehouse and reverse ETL jobs that send events (Measurement Protocol, HTTP APIs).

## Search patterns

Regular expressions to run with the agent's search tool or `rg -n` in each repository. Copy only the pattern inside the backticks:

- Segment: `analytics\.(track|page|screen)\(`
- RudderStack: `rudderanalytics\.(track|page)\(`
- Mixpanel: `mixpanel\.track\(`
- Amplitude: `amplitude\.(track|logEvent)\(|\.logEvent\(`
- PostHog: `posthog\.capture\(`
- gtag.js: `gtag\(\s*['"]event['"]`
- GTM data layer: `dataLayer\.push\(\s*\{[^}]*['"]?event['"]?\s*:`
- Measurement Protocol and HTTP API payloads: `"name"\s*:\s*"`
- The event name as a literal, one search per name: `['"]report_generated['"]`

- Server SDKs use the same method names (`track`, `capture`) on a client object; search for the event name too.
- Generated clients call methods, not strings: Ampli (`ampli.reportGenerated(...)`), Avo Codegen, Segment Typewriter, RudderTyper, and PostHog's typed client from `posthog-cli exp schema pull`. Search for the method name.
- Search with case-insensitive matching as well; variants ("Report Generated", "reportGenerated") are usually where a second producer lives.

## Dynamic names and gating

- Template strings and concatenation: `` `${feature}_clicked` ``, `"viewed_product_" + id`. These produce D04 patterns.
- Constant maps: `EVENTS.REPORT_GENERATED`. Search the constant and its call sites.
- Wrappers: `trackEvent("Report Generated", props)`. Search the wrapper's call sites.
- Feature flags around emitters: a disabled flag explains a stopped event. Record the flag key and its state per environment.
- Dead code: an emitter in a file nothing imports does not run.

## What to record per event

- Emitter location: file and line, or container, tag name and ID, or CDP function name.
- Gating condition: flag, consent check, environment check, user segment.
- Last change: date and commit, for example from `git log -S "report_generated" -- <path>`.
- Expected route to each tool: direct SDK, CDP destination, tag, warehouse sync.

## Labels and what they allow

- "Not observed in <tool>; emitter found at <location>, gated by <condition>": fix implementation, or correct the status. Not a retirement candidate.
- "No emitter found in the searched roots: <list>": a retirement candidate only when no consumer exists either, and only with owner approval and the retirement sequence in [reconciliation.md](reconciliation.md).
- Never write "not emitted" or "unused" without the second label, the list of roots searched and the consumer check.
- A test-account payload is often faster than a code search. Never submit forms, orders or consent choices on a live site without the user's approval for that test; use staging or a flagged test account.
