# Renames, merges and migrations per platform

A rename looks like a text change and behaves like a data migration. No tool checked rewrites raw event names that were already ingested. Every safe rename is the same pattern: change the producer at a known boundary, decide from evidence whether old and new may be read as one series, and never count one action twice. Platform behaviour below was checked on 2026-10-17; confirm it live before acting.

## Contents

- Classify the change
- The overlap test: when history may be merged
- Consumer inventory
- Cutover rules for every platform
- Dual emission, only when unavoidable
- GA4
- Mixpanel
- Amplitude
- PostHog
- Segment
- Warehouse
- Rename plan template

## Classify the change

- Label only (the raw name is acceptable, people find it hard to read): change the display name. Mixpanel Lexicon and Amplitude Data display names change the UI only. No code, no cutover.
- Raw rename, same meaning (case variant, synonym, convention change, collision): this file.
- Duplicates (two producers or spellings of one fact): fix the producers to one name. Unify history only when the overlap test below says the names are disjoint.
- Semantic change (trigger, counting unit or success condition changes): a new name, never the old name with a new meaning. Annotate the break in reports. Change control lives in the tracking-plan-builder skill.
- Retirement: stop emission at the source after a consumer check. A destination block loses everything sent while it is active.
- Existing consistent taxonomy in another style (Title Case, camelCase): do not migrate only for style. Map per destination and set display names.

## The overlap test: when history may be merged

A Mixpanel Lexicon merge, an Amplitude transformation, a PostHog action over two events and a warehouse union all add the two series together, for all history and for every old app version still sending. That is correct only when no occurrence was recorded under both names.

Classify every old and new pair before choosing a history method:

- Disjoint: each occurrence is recorded under at most one of the names. Examples: iOS sends `Purchase` and Android sends `purchase item` for their own purchases (Mixpanel's own merge example); one producer switches names at its boundary and no other producer records the same action.
- Overlapping: some occurrences are recorded under both names. Examples: a client event and a backend event for the same signup; old app versions still sending the old name after a backend event started covering the same actions; a GA4 Create event rule and its source event.

Evidence, recorded in the rename plan:

- For one recent full week, compare `count(old)`, `count(new)` and `count(old) + count(new)` per day against the source-of-truth table (user rows, report rows, orders).
- Or join on the entity ID (`user_id`, `report_id`, `order_id`): any ID recorded under both names for the same action is an overlap.
- Pass for disjoint: the summed series matches the source of truth within the tolerance agreed with the data owner (house default: within 2% every day), and no entity ID appears under both names.
- Pass for overlapping: one series matches the source of truth on its own and the summed series does not. That series is the authoritative one.

What to do with each:

- Disjoint: merge history (Lexicon merge, Amplitude transformation, PostHog action, warehouse union).
- Overlapping, and the authoritative series already covers the old name's history (a backend event that has always fired): keep only the authoritative series. Repoint every report that uses the duplicate, then hide it or give it the display name "(duplicate, retired)". Never merge it or add it to a metric.
- Overlapping, and the new series starts at the boundary: read the old name before the boundary and the new name after, with a date-bounded report or a warehouse mapping with `valid_to`. Do not hide the old name while any report still reads it across the boundary. Old-version traffic after the boundary is excluded, because the new series already counts it.

## Consumer inventory

Before any raw rename, list every consumer of the old name with an owner:

- Saved reports, dashboards, funnels, retention charts, cohorts and audiences in each analytics tool.
- GA4 key events, custom dimensions registered on renamed parameters, audiences, explorations, and Google Ads conversions created from the key event.
- Experiments and feature flags that use the event as a metric or targeting rule. In Amplitude, transformations apply when a chart or cohort generates results, and transformed user properties are applied before Experiment, Feature Flags and Guides & Surveys evaluate targeting, so a transformation can change cohorts and live targeting.
- CDP destination mappings, filters, Protocols or tracking plans, transformations.
- GTM: Custom Event triggers on the old dataLayer name, GA4 Event tags whose Event Name is the old name, and lookup tables that map it, in web and server containers.
- Warehouse models, dbt tests, BI dashboards and reverse ETL syncs that filter on the name.
- CRM workflows, lifecycle messaging triggers, alerts and monitors.
- Old app versions still in use, which will keep sending the old name.
- Offline or queued clients that send events late: events recorded before the cutover can arrive under the old name days later. Name a migration owner who decides how they are read.

Read-only tools help: GA4 MCP `run_report` with the event name dimension; Mixpanel MCP `Get-Events` and `Find-Duplicate-Groups`; Amplitude MCP `get_amp_taxonomy`; a warehouse query on `event_name` by producer and app version.

## Cutover rules for every platform

- Add the new name to every enforcement layer before release: Amplitude Data plan merged to main, Segment Protocols plan, RudderStack tracking plan (its "Drop events with unplanned event names" setting drops them). A blocking schema drops an unplanned name. Add its Lexicon description in Mixpanel at the same time.
- Set one release boundary per producer: deploy timestamp for web and server, container version publish time for a name set in GTM, app version for mobile. Record it in the changelog.
- Default: switch, do not dual emit. Reports read the old name before the boundary and the new name after, or a merged series when the overlap test says disjoint.
- Mobile: old versions keep sending the old name. Keep reading it until old-version volume is below the threshold agreed with the data owner (a common starting point is under 1% of the event's volume for 14 consecutive days), then retire the old mapping. If a server event now covers the same actions, old-version events are overlapping: exclude them after the boundary instead of reading both.
- Keep the old-to-new mapping in the changelog and the warehouse permanently.

## Dual emission, only when unavoidable

Use it only when a consumer cannot switch on the release date. Then:

- Send the legacy copy only to the consumer that still needs it, not to every destination.
- Fix an end date before the release.
- No metric, funnel or key event counts both names. Dual emission is overlapping by definition, so the two names are never merged.
- Put the shared occurrence key in a property (`event_id`) on both copies, but give each copy its own vendor dedupe key:
  - Amplitude deduplicates on `insert_id` for the same `device_id` within 7 days, and the event type is not part of the key. Two names with one `insert_id` means the second copy is silently dropped.
  - Segment deduplicates on `messageId` only, not on payload. Two calls with one `messageId` means the second is dropped.
  - Mixpanel's duplicate key includes the event name, so two names are never deduplicated against each other. Both are counted.
  - GA4 has no general event deduplication. It deduplicates only `purchase` events with the same `transaction_id`, on web streams; an empty `transaction_id` makes every such purchase a duplicate of the others. Never dual emit a key event to GA4.

## GA4

Facts that shape every GA4 rename:

- Event names are case sensitive and history is not rewritten. Modified and created events do not apply to historical data, and marking a key event does not change historic data.
- Renaming a key event removes its key-event status. Changing parameters without changing the name keeps it.
- An event can be marked as a key event before it is first received.
- Some names become key events automatically (`purchase` always; `add_to_cart`, `begin_checkout`, `view_item` and others with a linked Google Ads account and Ads Personalization on). See `platform-constraints.md`.

Preferred path: change the tag or code at the release boundary.

1. Mark the new name as a key event in advance when the old one was a key event (Admin, Data display, Events). Check the 30 key event limit on standard properties. Copy the old key event's counting method and default key event value, and record both in the rename plan: if they differ, key-event counts and the session key-event rate change at the boundary with no change in behaviour, and a later change to the counting method applies to future data only. Google's page (checked 2026-10-17) gives once per event as the default for most key events and once per session (legacy) as the default for key events created from Universal Analytics goals. Verify both on the live key events page. The Ads side (whether the conversion is primary or secondary, and which campaign goals use it) goes to the conversion owner.
2. Register custom dimensions for any renamed parameters. Check live whether the new dimension shows data from before registration; plan as if it does not.
3. Release the tag or code change. Verify that only the new name arrives from updated clients: in DebugView for gtag.js, GTM and Firebase; for Measurement Protocol senders (a server, Segment's GA4 Cloud destination), with the validation server and then Realtime or the BigQuery export, because DebugView does not show them.
4. Unmark the old key event once no producer sends it; earlier key-event history is preserved.
5. Update explorations, audiences and BigQuery queries to read the old name before the boundary and the new one after.
6. Inventory Google Ads conversions created from the old key event. Verify in Google Ads whether they follow the new name; plan as if they do not, and follow the current import docs to switch. The bidding decision belongs to the conversion owner (the conversion-goals-and-key-events skill; if it is not installed, hand the question to the user).
7. After release, check the key events list: only the intended key events are marked.

Name set in GTM: the same path, with the change made in the container. Edit the GA4 Event tag's Event Name (or the variable feeding it) in a workspace, check it in Preview and DebugView, then publish a new container version. The publish time on the Versions screen is the boundary. If the dataLayer event is renamed too, update every Custom Event trigger on it in the same version, or the tags stop firing.

Name set by Segment's GA4 Cloud destination: it sends through the Measurement Protocol, so Modify event never applies. Change the Custom Event mapping's Event Name or its Lowercase Event Name field (one mapping at a time; each change is a rename for GA4), or use a destination-scoped Protocols transformation. The mapping change time is the boundary.

Bridge path: Modify event, for client-side traffic you cannot redeploy quickly (for example a third-party script). Constraints from Google's help page:

- Admin, Data display, Events, Modify event. Editor role or higher. Configured per data stream.
- Calculated client side before data is sent to Analytics, so it does not apply to Measurement Protocol or other server-to-server events, including Segment's GA4 Cloud destination. The page does not say the same of created events; test before relying on Create event for server traffic.
- Takes an hour or more to apply, and never applies to historical data.
- Matching is case sensitive unless the operator says "(ignore case)". A rule for `Sign_Up` does not catch `sign_up`.
- Rules apply in list order, and modifications run before created events. A rule that depends on a renamed event must come after the rename.
- Up to 50 modifications and up to 50 created events.
- Narrowing a Google event such as `page_view` stops its collection elsewhere. Modifications based on `items` parameters are not possible with gtag.js.
- Remove the bridge rule after the source is fixed, so the rule does not hide a future regression.

Do not use Create event for a rename. Creating an event copies the source event into a new one and the source keeps being collected. If both are key events, or both feed Google Ads, one action counts twice. Create event fits a new derived event (a thank-you `page_view` becomes a lead event), with the "copy parameters from the source event" option set deliberately.

## Mixpanel

- Raw names cannot be renamed after ingestion.
- Display name in Lexicon: UI only. It does not modify stored data and does not affect exports.
- Merge in Lexicon (project owner only): combines separate events or event properties into one item without affecting raw data, shows a Merged status and can be unmerged. Autocapture events and user profile properties cannot be merged. Merge only names that pass the overlap test as disjoint. The docs do not state how merged items behave in saved reports, exports or the query API; before relying on a merge, compare one saved report and one export across the boundary, before and after the merge.
- Hide (admin or owner): hidden events and properties leave the query builder menus and are excluded from query results, including All Events and Flows. They are still ingested and still count toward the data allowance. Do not hide an old name while any report still reads it across the boundary.
- Block (owner only): stops storing new data and can be undone with Unblock, but data sent while blocked is never stored. Blocking takes a few hours; history is kept. Prefer stopping emission at the source.
- Data Standards (Enterprise) checks the display name when one is set. After setting friendly display names, lint the raw names separately.
- MCP: `Get-Events`, `List-Properties` and `Find-Duplicate-Groups` (discovery of duplicate and near-duplicate names) for the audit. `Edit-Event` and `Bulk-Edit-Events` set display names, descriptions, tags and visibility; `Dismiss-Duplicate-Group` and `Merge-Group` act on duplicate groups. These write to shared Lexicon. No read-only mode is documented, so run writes only from an approved change list, and run the overlap test before any `Merge-Group`. Mixpanel's `manage-lexicon` skill covers Lexicon cleanup.

## Amplitude

- Display names change the UI only, apply to active events and user properties in the tracking plan, and do not apply to custom events.
- Before release: add the new event to the tracking plan on a branch and merge it to main. If schema settings reject unexpected events, an unplanned new name is not ingested or stored.
- Before creating a merge transformation, save a chart that shows the old and new events separately across the boundary, and keep it as the verification evidence. Transformations apply retroactively, so once one exists the merged event can only be analysed as a whole.
- After release, only when the overlap test says disjoint: create a transformation that merges the old and new events into one. Transformations work at query time on historical and future data, do not change raw data (or Snowflake and Redshift data), are created only on main with Show transformations on, and are available in most charts. Limits: no transformation of a transformation, no transforming default user properties, and transformed entities are not available to block and drop filters. When the names overlap, give the duplicate a display name such as "(duplicate, retired)" and keep it out of every chart instead.
- Saved charts keep querying the old event until updated. Use Find and Replace on affected charts.
- Property case variants (`title`, `TITLE`) can be merged, and values (`true`, `TRUE`) renamed, with the same feature.
- Retiring the old name: prefer stopping emission at the source. In Amplitude, delete and block both stop ingestion immediately, both can be undone for future data (Restore, Unblock), and data sent while either is active is never stored. Prefer delete: it removes the event from chart dropdowns, keeps history visible in existing charts marked as deleted, and stops counting toward event volume and the instrumentation limit. Custom events cannot be blocked. Drop filters only hide data at query time.
- MCP: `get_amp_taxonomy` and `get_transformations` for the audit; `manage_amp_events` and `manage_amp_taxonomy` for changes on a branch. Deletes on main take effect immediately. Writes need Use MCP (write) and Update Tracking Plan; a role with only Use MCP (read) is the read-only setup. Amplitude's `taxonomy` and `tracking-plan-audit` skills audit naming.

## PostHog

- Actions combine several events into one for analysis and apply retroactively. A single-event action works as a readable "rename" for analysis. An action over two names sums them, so build it only for names that pass the overlap test as disjoint.
- Raw events are not rewritten by an action. Update insights to use the action across the boundary.
- Connect the PostHog MCP in read-only mode (`x-posthog-read-only: true` or `?readonly=true`) for audits.

## Segment

- Protocols Transformations (Business plan with the Protocols add-on; workspace owner or source admin) can rename events, properties and traits.
  - Source scope applies to all cloud-mode destinations, warehouses and S3 for that source. Destination scope applies to one cloud-mode destination. Device-mode destinations are not supported.
  - Not retroactive; Replay can resend history through a destination transformation.
  - Segment warns that original payloads are not easily recoverable once a transformation applies, and that source-level transformations are irrevocable. It treats source-scoped transformations as a temporary fix until the source is corrected; destination-scoped transformations can exist permanently, which suits a destination-specific name such as a GA4 mapping.
- When Protocols enforces the plan and an event's definition changes, use event versions: several definitions of one event, selected by the integer `context.protocols.event_version` in each Track call, so old clients validate against the old definition during cutover. Without the key, Segment validates against the oldest version. A generic `version` property does not trigger this. Verify the field name live.
- GA4 Cloud destination: it sends through the Measurement Protocol, so GA4 Modify event cannot bridge its names (see GA4 above). Changing the Event Name or the Lowercase Event Name field on a Custom Event mapping is itself a rename for GA4. Treat it with this file's cutover rules, one mapping at a time.

## Warehouse

- Never rewrite raw event rows. Keep a mapping table: `old_name`, `new_name`, `producer`, `valid_from`, `valid_to`, `history_method` (`merge`, `date_split` or `hide`), `reason`.
- Build one modelled event stream that maps old to new by producer and boundary. Union old and new only for disjoint pairs; for overlapping pairs take the old name only before `valid_to`.
- Test that daily counts across the boundary match the source of truth.

## Rename plan template

The example is a disjoint rename: three clients each record their own connections, so every occurrence is under exactly one name.

```yaml
rename:
  old_name: Data Source Connected
  new_name: data_source_connected
  kind: raw_rename_same_meaning
  reason: convention change to snake_case; same trigger (connection test passed) on every producer
  producers: [web, ios, android]          # who emits the old name, and when
  boundary:
    web: 2026-11-03T09:00:00Z
    ios: 5.8.0
    android: 5.8.0
  overlap:
    result: disjoint                      # disjoint or overlapping
    evidence: >-
      2026-10-05 to 2026-10-11: no data_source_id under both names;
      old + new daily counts within 1% of data_sources rows
    authoritative_series: ""              # only when overlapping
  consumers:
    - mixpanel: funnel "Data source setup" (owner: Product analyst)
    - warehouse: fct_data_source_events (owner: Data engineer)
  per_tool:
    mixpanel: Lexicon merge of old and new after release; verify one saved report and one export
    amplitude: plan updated on branch, merged before release; old-versus-new chart saved; transformation after release
    ga4: not sent                         # if sent: key event status, counting method and default value copied
    warehouse: mapping row, history_method merge
  # If overlapping: no merge. history_method hide (authoritative series covers history)
  # or date_split (old before the boundary, new after); name the authoritative series.
  dual_emission: none
  retire_old_after: old-version volume under 1% for 14 days
  approvals: [Data owner, Implementation owner]
```
