# Naming rules

Proposed file: `martech-context/naming-rules.md`. Replace every angle-bracket value. Keep the dated decisions in `martech-context/decisions.md`.

Owner: <name or role>
Approvers for new terms: <data owner>, <implementation owner>
Last reviewed: <YYYY-MM-DD>
Lint: copy the backticked terms of the two vocabulary sections into temporary `objects.txt` and `actions.txt` files (one term per line, plus `forbidden: <bad>=<approved>, ...` from the forbidden synonyms), then run `python3 <skill folder>/scripts/lint_event_names.py <list> --objects objects.txt --actions actions.txt`. The files and this page must list the same terms.

## Event names

- Pattern: `<object>_<action>`, lowercase ASCII snake_case, starting with a letter.
- Object: a singular noun from the object vocabulary below. Two words only when one is ambiguous (`member_invitation`).
- Action: a past-tense verb from the action vocabulary below. It names a completed fact.
- Asynchronous work gets separate events when the distinction drives a decision: `<object>_requested`, `<object>_succeeded`, `<object>_failed`, joined by a job or attempt ID property.
- Length: 40 characters at most (GA4). Names over 32 characters need a recorded reason.
- Never in a name: values (plan, format, step, version, date, ID), UI elements (button, link, modal), UI copy or translated labels, destinations (`ga_`, `mp_`), environments (`test`, `staging`), or the word "success".
- Context that does not change the fact goes in a property: `interaction_method`, `actor_type`, `locale`.
- Never a reserved name or prefix of any destination in `stack.md`.
- Spelling: <US or UK> English. <canceled or cancelled>, chosen once.

## Display labels

- Display label: Title Case of the canonical name (`report_export_succeeded` shows as "Report Export Succeeded").
- Set in: <Mixpanel Lexicon display names, Amplitude Data display names, PostHog descriptions or actions>.
- Display labels never replace a raw rename when the raw name is wrong or collides.

## Object vocabulary

- `<object>`: <definition, one line>
- `<object>`: <definition>

## Action vocabulary

- `created`: a record was persisted for the first time
- `<action>`: <definition>

Forbidden synonyms: <`cancelled` (use `canceled`), `signed_up` (use `registered`), `removed` (use `deleted`), `clicked`, ...>

## Property names

- Lowercase ASCII snake_case; 40 characters for event properties, 24 for user properties.
- One name, one type, one meaning across all events. Shared properties are defined once in `data-dictionary.md`.
- `_id` string identifiers; `_at` UTC timestamps; `_date` dates; `is_` or `has_` booleans; `_count` integers; units in the name for durations and sizes (`_ms`, `_bytes`).
- Money: amount plus `currency` (ISO 4217); state major or minor units.
- Enumerated values: lowercase snake_case codes, listed in the plan, with `unknown` where a value can be missing.
- Event-time copies of profile traits get explicit names (`plan_at_activation`).
- No personal data, free text or URLs with query strings.

## Destination exceptions

Recorded mappings where a destination receives a different name than the canonical one:

- GA4: `<canonical>` is sent as `<recommended event>` because <the trigger matches Google's meaning>.
- <destination>: <canonical> to <destination name>, because <connector transformation or legacy name>.
- GTM: dataLayer `<event>` is sent to GA4 as `<name>` by the GA4 Event tag `<tag name>`; the Event Name field is typed, never `{{Event}}`.

## Change process

- New event or property: lint, review checklist, approval by <approvers>, entry in the tracking plan.
- New vocabulary term: proposal with definition and the synonyms it forbids; approval by <data owner>.
- Rename: classify (label only, raw rename, duplicates, semantic change, retirement), inventory consumers, set the boundary, run the overlap test before any merge, follow the per-platform cutover.
- Exceptions to these rules: recorded in `decisions.md` with reason, owner and date.
