Skip to content

DENG-11155 - Newtab Widget aggregation table Update#9434

Open
land-edi wants to merge 1 commit into
mainfrom
update_widget_aggregation_table
Open

DENG-11155 - Newtab Widget aggregation table Update#9434
land-edi wants to merge 1 commit into
mainfrom
update_widget_aggregation_table

Conversation

@land-edi
Copy link
Copy Markdown
Contributor

@land-edi land-edi commented May 22, 2026

Description

This PR updates the firefox_desktop_derived.newtab_widgets_daily_v1, a daily aggregation of Firefox New Tab widget telemetry from firefox_desktop_stable.newtab_v1 with new segments and metrics.
New segments being added are (app_version, os, channel, locale, country).
A new metric widget_enabled_clients is added to track the number of clients with widget enabled.
Existing metrics (widget_setting_change_count, widget_utility_action_count) are updated to include more user actions.

Includes update to:

  • query.sql
  • metadata.yaml
  • schema.yaml
  • checks.sql
  • README.md

Related Tickets & Documents

Reviewer, please follow this checklist

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR widens the grain of firefox_desktop_derived.newtab_widgets_daily_v1 from (submission_date, widget_name) to (submission_date, app_version, os, channel, locale, country, widget_name), expands the user_action value lists feeding widget_setting_change_count and widget_utility_action_count (clock, teams, schedule, hour-format, timer-reset, expand/collapse, etc.), adds clustering on (channel, country), and introduces a new widget_enabled_clients metric sourced from metrics.string_list.newtab_widgets_enabled_list. checks.sql, metadata.yaml, schema.yaml, and README.md are updated to match.

Cross-cutting observations

  • Schema vs. query drift. The new widget_enabled_clients column is in query.sql output but missing from schema.yaml. Per the reviewer checklist, schema must be updated when fields are added — this is the most actionable item before merge.
  • widget_enabled_clients semantics. The new CTE pulls from metrics.string_list.newtab_widgets_enabled_list rather than the event stream, then LEFT JOINs back on a seven-key tuple including widget_name. This is worth scrutinizing: (a) the two widget_name namespaces (event extra vs. string_list value) may not line up identically; (b) clients with the widget enabled but no widget event on the day will be silently dropped; (c) it's a second full scan of newtab_v1. See the inline comment on the CTE for details.
  • Grain change is a real behavior change, not just a refactor. Multiplying by app_version × os × channel × locale × country will inflate row counts substantially (sparsely, but still). Worth a sanity-check on size and on whether downstream Looker explores assume the old grain. Since the table is still v1 and only recently introduced, an in-place change is reasonable, but the doc string "(initial version)" in the README is no longer literally true.
  • Documentation consistency. Several docs were partially updated for the new grain but a few spots still reference the old shape: the Mermaid diagram label, the is_unique comment in checks.sql, and the shortened metadata.yaml description (which dropped some useful detail). Inline notes on each.
  • Schema descriptions. A few of the newly-added field descriptions appear to be copy-pasted boilerplate that doesn't actually describe the stored value (app_version says "1.0.3"-style string but stores an integer major version; country says "name of the country" but stores a 2-letter code).

No tests live under tests/sql/.../newtab_widgets_daily_v1/; expanding test coverage is out of scope for this PR but worth flagging given the grain change and the cross-source join.

mode: NULLABLE
description: Set of language- and/or country-based preferences for a user interface.
- name: country
type: STRING
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: widget_enabled_clients is selected in query.sql (line 176) but is not declared in schema.yaml. The reviewer checklist explicitly calls this out: "If adding a new field to a query, ensure that the schema and dependent downstream schemas have been updated." Please add a widget_enabled_clients entry (INTEGER, NULLABLE) so the deploy reflects the new column. Otherwise the schema deploy will either drop the column or fail validation depending on how schema_update_option is configured.

- name: app_version
type: INTEGER
mode: NULLABLE
description: User visible version string (e.g. "1.0.3") for the browser.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: the description does not match the value being stored. The query stores mozfun.norm.browser_version_info(client_info.app_display_version).major_version cast to INT64 — i.e. just the integer major version (e.g. 142), not the user-visible display string like "1.0.3". Suggest updating the description to something like "Major version of the browser, parsed from client_info.app_display_version." so downstream consumers don't mis-interpret the column.

Comment on lines +22 to +26
- name: country
type: STRING
mode: NULLABLE
description: Name of the country in which the activity took place, as determined
by the IP geolocation.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: the description says "Name of the country" but the column stores normalized_country_code — a 2-letter ISO country code, not the country name. Recommend wording it as "ISO 3166-1 alpha-2 country code, derived from IP geolocation (normalized_country_code)."

- name: os
type: STRING
mode: NULLABLE
description: Set to "Other" if this message contained an unrecognized OS name.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: this description only states the fallback behavior ("Set to 'Other' if this message contained an unrecognized OS name.") and doesn't actually describe what the field is. Consider something like "Normalized operating system name (e.g. Windows, Mac, Linux); Other if unrecognized.". Same shape applies to locale and channel on the surrounding lines — they read as fragments rather than column definitions.

Comment on lines 154 to +194
@@ -115,4 +188,7 @@ FROM
aggregated AS agg
LEFT JOIN
user_action_array AS uaa
USING (submission_date, widget_name)
USING (submission_date, widget_name, app_version, os, channel, locale, country)
LEFT JOIN
enabled_users_aggregate AS eua
USING (submission_date, widget_name, app_version, os, channel, locale, country)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: there are a few concerns with how enabled_users_aggregate is wired in:

  1. Row loss for enable-only clients. eua is joined with LEFT JOIN agg → eua, so any (date, app_version, os, channel, locale, country, widget_name) combination that appears in metrics.string_list.newtab_widgets_enabled_list but has no widgets_impression / widgets_user_event / widgets_enabled event on that day will be silently dropped. If widget_enabled_clients is meant to count all clients with the widget enabled (which is what the PR description and README suggest), this likely under-counts. Consider FULL OUTER JOIN (with COALESCE on the join keys) — or document the intentional exclusion in the README under "Notes & Conventions".

  2. Different widget_name namespaces. widget_events.widget_name comes from event.extra['widget_name'], while eua.widget_name comes from values inside metrics.string_list.newtab_widgets_enabled_list. If those two surfaces use different identifiers (case, slug vs. display name, etc.) the join key will silently miss — and widget_enabled_clients will come back NULL for every row. Worth verifying with a sample query before merging that the value sets actually intersect.

  3. Duplicate scan of newtab_v1. The same source table is scanned a second time here with the same partition filter; the dimensions and aggregation could be folded into the existing aggregated CTE by adding COUNT(DISTINCT IF(<client has widget enabled>, client_id, NULL)) against an UNNEST joined in widget_events. Not required, but it would halve the scan cost and remove the join-key risk in (2).

Comment on lines 28 to +31
```mermaid
flowchart TD
A[Firefox Desktop Newtab Ping<br/>`firefox_desktop_stable.newtab_v1`] -->|filter @submission_date<br/>UNNEST events · widget events only<br/>GROUP BY widget_name| B[**This query**]
B --> C[Partitioned table<br/>time: `submission_date`<br/>cluster: `widget_name`]
B --> C[Partitioned table<br/>time: `submission_date`<br/>cluster: `widget_name`, `channel`, `country`]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: the Mermaid label still reads GROUP BY widget_name but the actual GROUP BY now includes submission_date, app_version, os, channel, locale, country, widget_name. Worth updating the diagram so it stays consistent with the grain table above and the How It Works step 3.

Comment on lines 2 to +4
description: |-
Daily aggregation of Firefox New Tab widget telemetry.
One row per widget per day, capturing impressions, user interactions,
enable/disable actions, and engagement metrics derived from the unified
widget telemetry shape in newtab_v1.
A daily aggregation of newtab actions on widgets (example: impressions, usage actions, clicks, etc...)
for Firefox desktop, partitioned by day.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: the new description is shorter and less precise than the one it replaces — it drops the explicit mention of impressions / user interactions / enable–disable / engagement metrics and that the data is derived from newtab_v1, and adds an etc... ellipsis. Since this description surfaces in dataset catalogs (Looker, BigQuery UI), it's worth keeping the more descriptive previous wording and just appending the new dimensions, e.g.:

description: |-
  Daily aggregation of Firefox New Tab widget telemetry derived from
  newtab_v1. One row per widget per day, broken down by app_version,
  os, channel, locale, and country, capturing impressions, user
  interactions, enable/disable actions, and engagement metrics.

Comment on lines 24 to +28
clustering:
fields:
- widget_name
- channel
- country
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: clustering order matters — BigQuery filters most efficiently on the leading clustering keys. The example query in README.md filters on country (and downstream Looker analyses are likely to filter on country/channel first), but the current order is widget_name, channel, country. If country/channel are expected to appear in WHERE more often than widget_name, consider reordering as country, channel, widget_name (or similar) to maximize pruning. Worth confirming the expected query patterns before locking this in, since cluster order is a deploy-time choice.

agg.widget_name,
submission_date,
widget_name,
eua.widget_enabled_clients,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: widget_engaged_clients and widget_enabled_clients differ by two letters and represent very different populations (engaged-via-event vs. enabled-via-string-list). Easy to misuse downstream. Recommend either renaming the new column to something less collidable (e.g. widget_active_enabled_clients, clients_with_widget_enabled) or adding an explicit row to the Notes & Conventions section of the README that contrasts the two definitions side-by-side, the same way widget_link_click_count is contrasted with widgets_visit_daily_v1.

@github-actions
Copy link
Copy Markdown
Contributor

Integration report for "DENG-11155 - Newtab Widget aggregation table Update"

sql.diff

Click to expand!
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/dags/bqetl_accounts_backend_external.py /tmp/workspace/generated-dags/dags/bqetl_accounts_backend_external.py
--- /tmp/workspace/main-generated-sql/dags/bqetl_accounts_backend_external.py	2026-05-22 22:03:46.587605426 +0000
+++ /tmp/workspace/generated-dags/dags/bqetl_accounts_backend_external.py	2026-05-22 22:03:45.856605352 +0000
@@ -55,6 +55,54 @@
     catchup=False,
 ) as dag:
 
+    accounts_backend_external__accounts__v1 = bigquery_etl_query(
+        task_id="accounts_backend_external__accounts__v1",
+        destination_table="accounts_v1",
+        dataset_id="accounts_backend_external",
+        project_id="moz-fx-data-shared-prod",
+        owner="akomar@mozilla.com",
+        email=["akomar@mozilla.com", "telemetry-alerts@mozilla.com"],
+        date_partition_parameter=None,
+        depends_on_past=False,
+        task_concurrency=1,
+    )
+
+    accounts_backend_external__emails__v1 = bigquery_etl_query(
+        task_id="accounts_backend_external__emails__v1",
+        destination_table="emails_v1",
+        dataset_id="accounts_backend_external",
+        project_id="moz-fx-data-shared-prod",
+        owner="akomar@mozilla.com",
+        email=["akomar@mozilla.com", "telemetry-alerts@mozilla.com"],
+        date_partition_parameter=None,
+        depends_on_past=False,
+        task_concurrency=1,
+    )
+
+    accounts_backend_external__nonprod_accounts__v1 = bigquery_etl_query(
+        task_id="accounts_backend_external__nonprod_accounts__v1",
+        destination_table="nonprod_accounts_v1",
+        dataset_id="accounts_backend_external",
+        project_id="moz-fx-data-shared-prod",
+        owner="akomar@mozilla.com",
+        email=["akomar@mozilla.com", "telemetry-alerts@mozilla.com"],
+        date_partition_parameter=None,
+        depends_on_past=False,
+        task_concurrency=1,
+    )
+
+    accounts_backend_external__nonprod_emails__v1 = bigquery_etl_query(
+        task_id="accounts_backend_external__nonprod_emails__v1",
+        destination_table="nonprod_emails_v1",
+        dataset_id="accounts_backend_external",
+        project_id="moz-fx-data-shared-prod",
+        owner="akomar@mozilla.com",
+        email=["akomar@mozilla.com", "telemetry-alerts@mozilla.com"],
+        date_partition_parameter=None,
+        depends_on_past=False,
+        task_concurrency=1,
+    )
+
     accounts_db_derived__accounts_aggregates__v1 = bigquery_etl_query(
         task_id="accounts_db_derived__accounts_aggregates__v1",
         destination_table="accounts_aggregates_v1",
Only in /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend: accounts
Only in /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend: nonprod_accounts
Only in /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod: accounts_backend_external
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend/accounts/metadata.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend/accounts/metadata.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend/accounts/metadata.yaml	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend/accounts/metadata.yaml	2026-05-22 22:03:43.098607626 +0000
@@ -0,0 +1,20 @@
+friendly_name: Accounts table from production FxA database
+description: |-
+  An authorized view on top of the `accounts_backend_external.accounts_v1` table
+  that only includes non-sensitive fields.
+  Some fields in this table are converted to a more user-friendly, BigQuery-native format:
+    - `uid` is converted from bytes to a hex string
+    - boolean integer columns are converted to BOOL
+    - timestamp columns are converted to TIMESTAMP
+
+  See https://mozilla.github.io/ecosystem-platform/reference/database-structure#database-fxa
+owners: []
+labels:
+  authorized: true
+workgroup_access:
+- role: roles/bigquery.dataViewer
+  members:
+  - workgroup:mozilla-confidential/data-viewers
+references:
+  view.sql:
+  - moz-fx-data-shared-prod.accounts_backend_external.accounts_v1
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend/accounts/view.sql /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend/accounts/view.sql
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend/accounts/view.sql	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend/accounts/view.sql	2026-05-22 22:03:43.082607639 +0000
@@ -0,0 +1,18 @@
+CREATE OR REPLACE VIEW
+  `moz-fx-data-shared-prod.accounts_backend.accounts`
+AS
+SELECT
+  uid,
+  emailVerified,
+  verifierVersion,
+  verifierSetAt,
+  createdAt,
+  locale,
+  lockedAt,
+  profileChangedAt,
+  keysChangedAt,
+  ecosystemAnonId,
+  disabledAt,
+  metricsOptOutAt,
+FROM
+  `moz-fx-data-shared-prod.accounts_backend_external.accounts_v1`
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend/nonprod_accounts/metadata.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend/nonprod_accounts/metadata.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend/nonprod_accounts/metadata.yaml	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend/nonprod_accounts/metadata.yaml	2026-05-22 22:03:43.004607703 +0000
@@ -0,0 +1,20 @@
+friendly_name: Accounts table from FxA database in stage environment
+description: |-
+  An authorized view on top of the `accounts_backend_external.nonprod_accounts_v1` table
+  that only includes non-sensitive fields.
+  Some fields in this table are converted to a more user-friendly, BigQuery-native format:
+    - `uid` is converted from bytes to a hex string
+    - boolean integer columns are converted to BOOL
+    - timestamp columns are converted to TIMESTAMP
+
+  See https://mozilla.github.io/ecosystem-platform/reference/database-structure#database-fxa
+owners: []
+labels:
+  authorized: true
+workgroup_access:
+- role: roles/bigquery.dataViewer
+  members:
+  - workgroup:mozilla-confidential/data-viewers
+references:
+  view.sql:
+  - moz-fx-data-shared-prod.accounts_backend_external.nonprod_accounts_v1
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend/nonprod_accounts/view.sql /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend/nonprod_accounts/view.sql
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend/nonprod_accounts/view.sql	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend/nonprod_accounts/view.sql	2026-05-22 22:03:43.044607670 +0000
@@ -0,0 +1,18 @@
+CREATE OR REPLACE VIEW
+  `moz-fx-data-shared-prod.accounts_backend.nonprod_accounts`
+AS
+SELECT
+  uid,
+  emailVerified,
+  verifierVersion,
+  verifierSetAt,
+  createdAt,
+  locale,
+  lockedAt,
+  profileChangedAt,
+  keysChangedAt,
+  ecosystemAnonId,
+  disabledAt,
+  metricsOptOutAt,
+FROM
+  `moz-fx-data-shared-prod.accounts_backend_external.nonprod_accounts_v1`
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/accounts_v1/metadata.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/accounts_v1/metadata.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/accounts_v1/metadata.yaml	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/accounts_v1/metadata.yaml	2026-05-22 22:03:42.967607734 +0000
@@ -0,0 +1,25 @@
+friendly_name: Accounts table from production FxA database
+description: |
+  A mirror of the `accounts` table from the production FxA CloudSQL database, updated daily to match the current state of the table. Some fields in this table are converted to a more user-friendly, BigQuery-native format:
+    - `uid` is converted from bytes to a hex string
+    - boolean integer columns are converted to BOOL
+    - timestamp columns are converted to TIMESTAMP
+
+  See https://mozilla.github.io/ecosystem-platform/reference/database-structure#database-fxa
+owners:
+- akomar@mozilla.com
+labels:
+  application: accounts_backend
+  schedule: daily
+  dag: bqetl_accounts_backend_external
+  owner1: akomar
+scheduling:
+  dag_name: bqetl_accounts_backend_external
+  date_partition_parameter: null
+workgroup_access:
+- role: roles/bigquery.dataViewer
+  members:
+  - workgroup:accounts-confidential/data-viewers
+references:
+  query.sql:
+  - EXTERNAL_QUERY('moz-fx-fxa-prod.us.fxa-rds-prod-prod-fxa', 'SELECT\n         uid,\n         normalizedEmail,\n         email,\n         emailVerified,\n         verifierVersion,\n         verifierSetAt,\n         createdAt,\n         locale,\n         lockedAt,\n         profileChangedAt,\n         keysChangedAt,\n         ecosystemAnonId,\n         disabledAt,\n         metricsOptOutAt\n       FROM\n         accounts\n    ')
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/accounts_v1/query.sql /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/accounts_v1/query.sql
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/accounts_v1/query.sql	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/accounts_v1/query.sql	2026-05-22 22:03:43.044607670 +0000
@@ -0,0 +1,37 @@
+SELECT
+  TO_HEX(uid) AS uid,
+  normalizedEmail,
+  email,
+  SAFE_CAST(emailVerified AS BOOL) AS emailVerified,
+  verifierVersion,
+  SAFE.TIMESTAMP_MILLIS(SAFE_CAST(verifierSetAt AS INT)) AS verifierSetAt,
+  SAFE.TIMESTAMP_MILLIS(SAFE_CAST(createdAt AS INT)) AS createdAt,
+  locale,
+  SAFE.TIMESTAMP_MILLIS(SAFE_CAST(lockedAt AS INT)) AS lockedAt,
+  SAFE.TIMESTAMP_MILLIS(SAFE_CAST(profileChangedAt AS INT)) AS profileChangedAt,
+  SAFE.TIMESTAMP_MILLIS(SAFE_CAST(keysChangedAt AS INT)) AS keysChangedAt,
+  ecosystemAnonId,
+  SAFE.TIMESTAMP_MILLIS(SAFE_CAST(disabledAt AS INT)) AS disabledAt,
+  SAFE.TIMESTAMP_MILLIS(SAFE_CAST(metricsOptOutAt AS INT)) AS metricsOptOutAt,
+FROM
+  EXTERNAL_QUERY(
+    "moz-fx-fxa-prod.us.fxa-rds-prod-prod-fxa",
+    """SELECT
+         uid,
+         normalizedEmail,
+         email,
+         emailVerified,
+         verifierVersion,
+         verifierSetAt,
+         createdAt,
+         locale,
+         lockedAt,
+         profileChangedAt,
+         keysChangedAt,
+         ecosystemAnonId,
+         disabledAt,
+         metricsOptOutAt
+       FROM
+         accounts
+    """
+  )
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/accounts_v1/schema.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/accounts_v1/schema.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/accounts_v1/schema.yaml	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/accounts_v1/schema.yaml	2026-05-22 22:03:43.044607670 +0000
@@ -0,0 +1,47 @@
+fields:
+  - name: uid
+    type: STRING
+    mode: NULLABLE
+    description: |-
+      Account ID in hexadecimal format.
+      FxA stores this as bytes, for purposes of logging or integration
+      with other systems we convert it to a hex string.
+  - name: normalizedEmail
+    type: STRING
+    mode: NULLABLE
+  - name: email
+    type: STRING
+    mode: NULLABLE
+  - name: emailVerified
+    type: BOOLEAN
+    mode: NULLABLE
+  - name: verifierVersion
+    type: INTEGER
+    mode: NULLABLE
+  - name: verifierSetAt
+    type: TIMESTAMP
+    mode: NULLABLE
+  - name: createdAt
+    type: TIMESTAMP
+    mode: NULLABLE
+  - name: locale
+    type: STRING
+    mode: NULLABLE
+  - name: lockedAt
+    type: TIMESTAMP
+    mode: NULLABLE
+  - name: profileChangedAt
+    type: TIMESTAMP
+    mode: NULLABLE
+  - name: keysChangedAt
+    type: TIMESTAMP
+    mode: NULLABLE
+  - name: ecosystemAnonId
+    type: STRING
+    mode: NULLABLE
+  - name: disabledAt
+    type: TIMESTAMP
+    mode: NULLABLE
+  - name: metricsOptOutAt
+    type: TIMESTAMP
+    mode: NULLABLE
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/dataset_metadata.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/dataset_metadata.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/dataset_metadata.yaml	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/dataset_metadata.yaml	2026-05-22 22:03:43.044607670 +0000
@@ -0,0 +1,14 @@
+friendly_name: Firefox Accounts Backend External
+description: |-
+  Data extracted from the FxA backend services databases.
+  See https://mozilla.github.io/ecosystem-platform/reference/database-structure#database-fxa for more information.
+
+  Access to this dataset is restricted to accounts-confidential workgroup because some tables here contain sensitive data.
+  `mozilla-confidential` user-facing views are available in the `accounts_backend` dataset.
+dataset_base_acl: restricted
+user_facing: false
+labels: {}
+workgroup_access:
+- role: roles/bigquery.dataViewer
+  members:
+  - workgroup:accounts-confidential/data-viewers
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/emails_v1/metadata.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/emails_v1/metadata.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/emails_v1/metadata.yaml	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/emails_v1/metadata.yaml	2026-05-22 22:03:43.004607703 +0000
@@ -0,0 +1,27 @@
+friendly_name: Emails table from production FxA database
+description: |-
+  A mirror of the `emails` table from the production FxA CloudSQL database,
+  updated daily to match the current state of the table.
+  Some fields in this table are converted to a more user-friendly, BigQuery-native format:
+    - `uid` is converted from bytes to a hex string
+    - boolean integer columns are converted to BOOL
+    - timestamp columns are converted to TIMESTAMP
+
+  See https://mozilla.github.io/ecosystem-platform/reference/database-structure#database-fxa
+owners:
+- akomar@mozilla.com
+labels:
+  application: accounts_backend
+  schedule: daily
+  dag: bqetl_accounts_backend_external
+  owner1: akomar
+scheduling:
+  dag_name: bqetl_accounts_backend_external
+  date_partition_parameter: null
+workgroup_access:
+- role: roles/bigquery.dataViewer
+  members:
+  - workgroup:accounts-confidential/data-viewers
+references:
+  query.sql:
+  - EXTERNAL_QUERY('moz-fx-fxa-prod.us.fxa-rds-prod-prod-fxa', 'SELECT\n         id,\n         normalizedEmail,\n         email,\n         uid,\n         isVerified,\n         isPrimary,\n         verifiedAt,\n         createdAt\n       FROM\n         emails\n    ')
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/emails_v1/query.sql /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/emails_v1/query.sql
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/emails_v1/query.sql	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/emails_v1/query.sql	2026-05-22 22:03:43.044607670 +0000
@@ -0,0 +1,25 @@
+SELECT
+  id,
+  normalizedEmail,
+  email,
+  TO_HEX(uid) AS uid,
+  SAFE_CAST(isVerified AS BOOL) AS isVerified,
+  SAFE_CAST(isPrimary AS BOOL) AS isPrimary,
+  SAFE.TIMESTAMP_MILLIS(SAFE_CAST(verifiedAt AS INT)) AS verifiedAt,
+  SAFE.TIMESTAMP_MILLIS(SAFE_CAST(createdAt AS INT)) AS createdAt,
+FROM
+  EXTERNAL_QUERY(
+    "moz-fx-fxa-prod.us.fxa-rds-prod-prod-fxa",
+    """SELECT
+         id,
+         normalizedEmail,
+         email,
+         uid,
+         isVerified,
+         isPrimary,
+         verifiedAt,
+         createdAt
+       FROM
+         emails
+    """
+  )
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/emails_v1/schema.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/emails_v1/schema.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/emails_v1/schema.yaml	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/emails_v1/schema.yaml	2026-05-22 22:03:43.044607670 +0000
@@ -0,0 +1,29 @@
+fields:
+- name: id
+  type: INTEGER
+  mode: NULLABLE
+- name: normalizedEmail
+  type: STRING
+  mode: NULLABLE
+- name: email
+  type: STRING
+  mode: NULLABLE
+- name: uid
+  type: STRING
+  mode: NULLABLE
+  description: |-
+    Account ID in hexadecimal format.
+    FxA stores this as bytes, for purposes of logging or integration
+    with other systems we convert it to a hex string.
+- name: isVerified
+  type: BOOLEAN
+  mode: NULLABLE
+- name: isPrimary
+  type: BOOLEAN
+  mode: NULLABLE
+- name: verifiedAt
+  type: TIMESTAMP
+  mode: NULLABLE
+- name: createdAt
+  type: TIMESTAMP
+  mode: NULLABLE
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_accounts_v1/metadata.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_accounts_v1/metadata.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_accounts_v1/metadata.yaml	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_accounts_v1/metadata.yaml	2026-05-22 22:03:43.004607703 +0000
@@ -0,0 +1,25 @@
+friendly_name: Accounts table from FxA database in stage environment
+description: |
+  A mirror of the `accounts` table from the staging FxA CloudSQL database, updated daily to match the current state of the table. Some fields in this table are converted to a more user-friendly, BigQuery-native format:
+    - `uid` is converted from bytes to a hex string
+    - boolean integer columns are converted to BOOL
+    - timestamp columns are converted to TIMESTAMP
+
+  See https://mozilla.github.io/ecosystem-platform/reference/database-structure#database-fxa
+owners:
+- akomar@mozilla.com
+labels:
+  application: accounts_backend
+  schedule: daily
+  dag: bqetl_accounts_backend_external
+  owner1: akomar
+scheduling:
+  dag_name: bqetl_accounts_backend_external
+  date_partition_parameter: null
+workgroup_access:
+- role: roles/bigquery.dataViewer
+  members:
+  - workgroup:accounts-confidential/data-viewers
+references:
+  query.sql:
+  - EXTERNAL_QUERY('moz-fx-fxa-nonprod.us.fxa-rds-nonprod-stage-fxa', 'SELECT\n         uid,\n         normalizedEmail,\n         email,\n         emailVerified,\n         verifierVersion,\n         verifierSetAt,\n         createdAt,\n         locale,\n         lockedAt,\n         profileChangedAt,\n         keysChangedAt,\n         ecosystemAnonId,\n         disabledAt,\n         metricsOptOutAt\n       FROM\n         accounts\n    ')
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_accounts_v1/query.sql /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_accounts_v1/query.sql
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_accounts_v1/query.sql	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_accounts_v1/query.sql	2026-05-22 22:03:43.044607670 +0000
@@ -0,0 +1,37 @@
+SELECT
+  TO_HEX(uid) AS uid,
+  normalizedEmail,
+  email,
+  SAFE_CAST(emailVerified AS BOOL) AS emailVerified,
+  verifierVersion,
+  SAFE.TIMESTAMP_MILLIS(SAFE_CAST(verifierSetAt AS INT)) AS verifierSetAt,
+  SAFE.TIMESTAMP_MILLIS(SAFE_CAST(createdAt AS INT)) AS createdAt,
+  locale,
+  SAFE.TIMESTAMP_MILLIS(SAFE_CAST(lockedAt AS INT)) AS lockedAt,
+  SAFE.TIMESTAMP_MILLIS(SAFE_CAST(profileChangedAt AS INT)) AS profileChangedAt,
+  SAFE.TIMESTAMP_MILLIS(SAFE_CAST(keysChangedAt AS INT)) AS keysChangedAt,
+  ecosystemAnonId,
+  SAFE.TIMESTAMP_MILLIS(SAFE_CAST(disabledAt AS INT)) AS disabledAt,
+  SAFE.TIMESTAMP_MILLIS(SAFE_CAST(metricsOptOutAt AS INT)) AS metricsOptOutAt,
+FROM
+  EXTERNAL_QUERY(
+    "moz-fx-fxa-nonprod.us.fxa-rds-nonprod-stage-fxa",
+    """SELECT
+         uid,
+         normalizedEmail,
+         email,
+         emailVerified,
+         verifierVersion,
+         verifierSetAt,
+         createdAt,
+         locale,
+         lockedAt,
+         profileChangedAt,
+         keysChangedAt,
+         ecosystemAnonId,
+         disabledAt,
+         metricsOptOutAt
+       FROM
+         accounts
+    """
+  )
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_accounts_v1/schema.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_accounts_v1/schema.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_accounts_v1/schema.yaml	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_accounts_v1/schema.yaml	2026-05-22 22:03:43.044607670 +0000
@@ -0,0 +1,47 @@
+fields:
+- name: uid
+  type: STRING
+  mode: NULLABLE
+  description: |-
+    Account ID in hexadecimal format.
+    FxA stores this as bytes, for purposes of logging or integration
+    with other systems we convert it to a hex string.
+- name: normalizedEmail
+  type: STRING
+  mode: NULLABLE
+- name: email
+  type: STRING
+  mode: NULLABLE
+- name: emailVerified
+  type: BOOLEAN
+  mode: NULLABLE
+- name: verifierVersion
+  type: INTEGER
+  mode: NULLABLE
+- name: verifierSetAt
+  type: TIMESTAMP
+  mode: NULLABLE
+- name: createdAt
+  type: TIMESTAMP
+  mode: NULLABLE
+- name: locale
+  type: STRING
+  mode: NULLABLE
+- name: lockedAt
+  type: TIMESTAMP
+  mode: NULLABLE
+- name: profileChangedAt
+  type: TIMESTAMP
+  mode: NULLABLE
+- name: keysChangedAt
+  type: TIMESTAMP
+  mode: NULLABLE
+- name: ecosystemAnonId
+  type: STRING
+  mode: NULLABLE
+- name: disabledAt
+  type: TIMESTAMP
+  mode: NULLABLE
+- name: metricsOptOutAt
+  type: TIMESTAMP
+  mode: NULLABLE
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_emails_v1/metadata.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_emails_v1/metadata.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_emails_v1/metadata.yaml	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_emails_v1/metadata.yaml	2026-05-22 22:03:43.004607703 +0000
@@ -0,0 +1,27 @@
+friendly_name: Emails table from FxA database in stage environment
+description: |-
+  A mirror of the `emails` table from the staging FxA CloudSQL database,
+  updated daily to match the current state of the table.
+  Some fields in this table are converted to a more user-friendly, BigQuery-native format:
+    - `uid` is converted from bytes to a hex string
+    - boolean integer columns are converted to BOOL
+    - timestamp columns are converted to TIMESTAMP
+
+  See https://mozilla.github.io/ecosystem-platform/reference/database-structure#database-fxa
+owners:
+- akomar@mozilla.com
+labels:
+  application: accounts_backend
+  schedule: daily
+  dag: bqetl_accounts_backend_external
+  owner1: akomar
+scheduling:
+  dag_name: bqetl_accounts_backend_external
+  date_partition_parameter: null
+workgroup_access:
+- role: roles/bigquery.dataViewer
+  members:
+  - workgroup:accounts-confidential/data-viewers
+references:
+  query.sql:
+  - EXTERNAL_QUERY('moz-fx-fxa-nonprod.us.fxa-rds-nonprod-stage-fxa', 'SELECT\n         id,\n         normalizedEmail,\n         email,\n         uid,\n         isVerified,\n         isPrimary,\n         verifiedAt,\n         createdAt\n       FROM\n         emails\n    ')
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_emails_v1/query.sql /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_emails_v1/query.sql
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_emails_v1/query.sql	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_emails_v1/query.sql	2026-05-22 22:03:43.044607670 +0000
@@ -0,0 +1,25 @@
+SELECT
+  id,
+  normalizedEmail,
+  email,
+  TO_HEX(uid) AS uid,
+  SAFE_CAST(isVerified AS BOOL) AS isVerified,
+  SAFE_CAST(isPrimary AS BOOL) AS isPrimary,
+  SAFE.TIMESTAMP_MILLIS(SAFE_CAST(verifiedAt AS INT)) AS verifiedAt,
+  SAFE.TIMESTAMP_MILLIS(SAFE_CAST(createdAt AS INT)) AS createdAt,
+FROM
+  EXTERNAL_QUERY(
+    "moz-fx-fxa-nonprod.us.fxa-rds-nonprod-stage-fxa",
+    """SELECT
+         id,
+         normalizedEmail,
+         email,
+         uid,
+         isVerified,
+         isPrimary,
+         verifiedAt,
+         createdAt
+       FROM
+         emails
+    """
+  )
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_emails_v1/schema.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_emails_v1/schema.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_emails_v1/schema.yaml	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/accounts_backend_external/nonprod_emails_v1/schema.yaml	2026-05-22 22:03:43.044607670 +0000
@@ -0,0 +1,29 @@
+fields:
+- name: id
+  type: INTEGER
+  mode: NULLABLE
+- name: normalizedEmail
+  type: STRING
+  mode: NULLABLE
+- name: email
+  type: STRING
+  mode: NULLABLE
+- name: uid
+  type: STRING
+  mode: NULLABLE
+  description: |-
+    Account ID in hexadecimal format.
+    FxA stores this as bytes, for purposes of logging or integration
+    with other systems we convert it to a hex string.
+- name: isVerified
+  type: BOOLEAN
+  mode: NULLABLE
+- name: isPrimary
+  type: BOOLEAN
+  mode: NULLABLE
+- name: verifiedAt
+  type: TIMESTAMP
+  mode: NULLABLE
+- name: createdAt
+  type: TIMESTAMP
+  mode: NULLABLE
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_historical_v1/metadata.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_historical_v1/metadata.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_historical_v1/metadata.yaml	2026-05-22 22:03:46.918605523 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_historical_v1/metadata.yaml	2026-05-22 22:03:43.021607689 +0000
@@ -24,7 +24,7 @@
 references:
   query.sql:
   - moz-fx-data-shared-prod.accounts_backend_derived.users_services_last_seen_v1
-  - moz-fx-data-shared-prod.accounts_db_external.fxa_emails_v1
+  - moz-fx-data-shared-prod.accounts_backend_external.emails_v1
   - moz-fx-data-shared-prod.braze_derived.fxa_win10_users_historical_v1
   - moz-fx-data-shared-prod.braze_derived.users_v1
   - moz-fx-data-shared-prod.firefox_desktop.fx_accounts
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_historical_v1/query.sql /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_historical_v1/query.sql
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_historical_v1/query.sql	2026-05-22 22:03:46.937605529 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_historical_v1/query.sql	2026-05-22 22:03:43.046607668 +0000
@@ -96,7 +96,7 @@
     `moz-fx-data-shared-prod.braze_derived.users_v1` AS braze_users
     ON inactive.user_id_sha256 = braze_users.fxa_id_sha256
   LEFT JOIN
-    `moz-fx-data-shared-prod.accounts_db_external.fxa_emails_v1` AS fxa_emails
+    `moz-fx-data-shared-prod.accounts_backend_external.emails_v1` AS fxa_emails
     ON inactive.user_id_sha256 = TO_HEX(SHA256(fxa_emails.uid))
   -- some users have multiple email addresses in this table, only use primary
     AND fxa_emails.isPrimary = TRUE
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/kitsune_retrieval_index_v1/metadata.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/kitsune_retrieval_index_v1/metadata.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/kitsune_retrieval_index_v1/metadata.yaml	2026-05-22 22:03:46.937605529 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/kitsune_retrieval_index_v1/metadata.yaml	2026-05-22 22:03:43.046607668 +0000
@@ -42,6 +42,7 @@
   query.sql:
   - moz-fx-data-shared-prod.sumo_syndicate.kitsune_questions_plus
   - moz-fx-data-shared-prod.sumo_syndicate.kitsune_answers_raw
+  - moz-fx-data-shared-prod.static.cx_product_mappings_v1
 monitoring:
   enabled: true
 require_column_descriptions: true
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/kitsune_retrieval_index_v1/query.sql /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/kitsune_retrieval_index_v1/query.sql
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/kitsune_retrieval_index_v1/query.sql	2026-05-22 22:03:46.937605529 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/kitsune_retrieval_index_v1/query.sql	2026-05-22 22:03:43.046607668 +0000
@@ -16,7 +16,7 @@
     q.question_id,
     q.created_date AS question_created_at,
     q.creator_username AS question_creator,
-    mozfun.customer_experience.normalize_product(q.product, 'Kitsune') AS product,
+    COALESCE(m.product_mapping, q.product) AS product,
     q.locale,
     q.topic,
     q.tier1_topic,
@@ -26,6 +26,10 @@
     q.question_content AS content
   FROM
     `moz-fx-data-shared-prod.sumo_syndicate.kitsune_questions_plus` q
+  LEFT JOIN
+    `moz-fx-data-shared-prod.static.cx_product_mappings_v1` m
+    ON m.product = q.product
+    AND m.source = 'Kitsune'
   WHERE
     q.is_spam = FALSE
     AND q.is_locked = FALSE
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/kitsune_retrieval_index_v1/schema.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/kitsune_retrieval_index_v1/schema.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/kitsune_retrieval_index_v1/schema.yaml	2026-05-22 22:03:46.937605529 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/kitsune_retrieval_index_v1/schema.yaml	2026-05-22 22:03:43.046607668 +0000
@@ -23,8 +23,8 @@
   type: STRING
   mode: NULLABLE
   description: Mozilla product associated with the support question.
-      Normalized via `mozfun.customer_experience.normalize_product`
-      (source = 'Kitsune'); unknown raw values map to 'Other'.
+      Normalized via `moz-fx-data-shared-prod.static.cx_product_mappings_v1`
+      (source = 'Kitsune'); falls back to the raw upstream value when no mapping exists.
 - name: locale
   type: STRING
   mode: NULLABLE
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/zendesk_retrieval_index_v1/README.md /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/zendesk_retrieval_index_v1/README.md
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/zendesk_retrieval_index_v1/README.md	2026-05-22 22:03:46.920605524 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/zendesk_retrieval_index_v1/README.md	2026-05-22 22:03:43.030607682 +0000
@@ -9,7 +9,7 @@
 | | |
 |---|---|
 | **Grain** | One row per Zendesk ticket (keyed by `creation_date`, `ticket_id`) |
-| **Source** | `moz-fx-data-shared-prod.zendesk_syndicate.ticket` (+ joins to `group`, `user`, `ticket_field_history`, `ticket_tag`; product normalized via `mozfun.customer_experience.normalize_product`) |
+| **Source** | `moz-fx-data-shared-prod.zendesk_syndicate.ticket` (+ joins to `group`, `user`, `ticket_field_history`, `ticket_tag`, and `static.cx_product_mappings_v1`) |
 | **DAG** | `bqetl_analytics_tables` · daily · incremental |
 | **Partitioning** | `creation_date` *(partition filter required)* |
 | **Clustering** | `product`, `locale` |
@@ -206,7 +206,7 @@
 ## 🔧 Implementation Notes
 
 - Incremental: one partition written per run, filtered by `DATE(ticket.created_at) = @submission_date`.
-- Source is read from the shared-prod syndicate: `zendesk_syndicate.ticket`, with joins to `group`, `user`, `ticket_field_history`, and `ticket_tag`. Product normalization uses the `mozfun.customer_experience.normalize_product` UDF.
+- Source is read from the shared-prod syndicate: `zendesk_syndicate.ticket`, with joins to `group`, `user`, `ticket_field_history`, `ticket_tag`, and `static.cx_product_mappings_v1`.
 - **Appbot classification** uses `mozfun.customer_experience.classify_appbot_group` to tag tickets and exclude the `Appbot - Non-English` bucket.
 - **Automation classification** uses `mozfun.customer_experience.is_automated`; tickets that transitioned `solved → open` (reopens) are recategorized as agent-handled.
 - **Test-ticket exclusion** uses a tag regex (`(^|[-_])test([-_]|$)`) plus an explicit `qatest` match — narrower than a naive `LIKE '%test%'`.
@@ -219,7 +219,7 @@
 
 - `recency_score` is **only on the `customer_experience.zendesk_retrieval_index` view**, not on this underlying table. It is computed at read time as `EXP(-DATE_DIFF(CURRENT_DATE(), creation_date, DAY) / 30)` — 30-day exponential decay; 1.0 for today, ~0.37 after 30 days. Always reflects freshness relative to the current query date, so backfills don't have to recompute it.
 - `ticket_sentiment_score` ranges -1.0 (very negative) to 1.0 (very positive), 0 is neutral.
-- `product` is normalized from raw Zendesk `custom_product` via `mozfun.customer_experience.normalize_product` (source = 'Zendesk'); unknown raw values map to 'Other'.
+- `product` is normalized from raw Zendesk `custom_product` via `static.cx_product_mappings_v1` (source = 'Zendesk'); falls back to the raw value when no mapping exists.
 - `type` is always "ticket"; future versions may include additional content types.
 - `embedding` is a dense float array suitable for cosine similarity or nearest-neighbor search.
 
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/zendesk_retrieval_index_v1/metadata.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/zendesk_retrieval_index_v1/metadata.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/zendesk_retrieval_index_v1/metadata.yaml	2026-05-22 22:03:46.937605529 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/zendesk_retrieval_index_v1/metadata.yaml	2026-05-22 22:03:43.046607668 +0000
@@ -45,6 +45,7 @@
   - moz-fx-data-shared-prod.zendesk_syndicate.ticket_field_history
   - moz-fx-data-shared-prod.zendesk_syndicate.group
   - moz-fx-data-shared-prod.zendesk_syndicate.user
+  - moz-fx-data-shared-prod.static.cx_product_mappings_v1
 monitoring:
   enabled: true
 require_column_descriptions: true
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/zendesk_retrieval_index_v1/query.sql /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/zendesk_retrieval_index_v1/query.sql
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/zendesk_retrieval_index_v1/query.sql	2026-05-22 22:03:46.937605529 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/zendesk_retrieval_index_v1/query.sql	2026-05-22 22:03:43.046607668 +0000
@@ -110,7 +110,7 @@
     ticket.subject AS title,
     custom_appbot_star_rating AS star_rating,
     ticket.description AS content,
-    mozfun.customer_experience.normalize_product(ticket.custom_product, 'Zendesk') AS product,
+    COALESCE(pm.product_mapping, ticket.custom_product) AS product,
     u.locale,
     custom_category,
     g.name AS group_name,
@@ -134,6 +134,10 @@
   LEFT JOIN
     human_auto_flag ha
     ON ticket.id = ha.ticket_id
+  LEFT JOIN
+    `moz-fx-data-shared-prod.static.cx_product_mappings_v1` pm
+    ON pm.product = ticket.custom_product
+    AND pm.source = 'Zendesk'
   WHERE
     DATE(ticket.created_at) = @submission_date
     AND COALESCE(ticket_group, 'All Other Tickets') != 'Appbot - Non-English'
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/zendesk_retrieval_index_v1/schema.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/zendesk_retrieval_index_v1/schema.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/zendesk_retrieval_index_v1/schema.yaml	2026-05-22 22:03:46.937605529 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/customer_experience_derived/zendesk_retrieval_index_v1/schema.yaml	2026-05-22 22:03:43.046607668 +0000
@@ -49,8 +49,8 @@
   type: STRING
   mode: NULLABLE
   description: Mozilla product associated with the support ticket.
-      Normalized via `mozfun.customer_experience.normalize_product`
-      (source = 'Zendesk'); unknown raw values map to 'Other'.
+      Normalized via `moz-fx-data-shared-prod.static.cx_product_mappings_v1`
+      (source = 'Zendesk'); falls back to the raw `custom_product` value when no mapping exists.
 - name: locale
   type: STRING
   mode: NULLABLE
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/firefox_accounts_derived/docker_fxa_admin_server_sanitized_v1/schema.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/firefox_accounts_derived/docker_fxa_admin_server_sanitized_v1/schema.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/firefox_accounts_derived/docker_fxa_admin_server_sanitized_v1/schema.yaml	2026-05-22 22:03:46.930605527 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/firefox_accounts_derived/docker_fxa_admin_server_sanitized_v1/schema.yaml	2026-05-22 22:03:43.002607705 +0000
@@ -5,17 +5,13 @@
 - name: logName
   type: STRING
   mode: NULLABLE
-  description: The resource name of the log to which this log entry belongs.
 - name: resource
   type: RECORD
   mode: NULLABLE
-  description: The monitored resource that produced this log entry.
   fields:
   - name: type
     type: STRING
     mode: NULLABLE
-    description: The monitored resource type. For example, the type of a Compute Engine
-      VM instance is `gce_instance`.
   - name: labels
     type: RECORD
     mode: NULLABLE
@@ -32,12 +28,9 @@
 - name: textPayload
   type: STRING
   mode: NULLABLE
-  description: The log entry payload, represented as a Unicode string (UTF-8).
 - name: jsonPayload
   type: RECORD
   mode: NULLABLE
-  description: The log entry payload, represented as a structure that is expressed
-    as a JSON object.
   fields:
   - name: severity
     type: FLOAT
@@ -115,94 +108,61 @@
 - name: receiveTimestamp
   type: TIMESTAMP
   mode: NULLABLE
-  description: The time the log entry was received by Logging.
 - name: severity
   type: STRING
   mode: NULLABLE
-  description: The severity of the log entry. The default value is `LogSeverity.DEFAULT`.
 - name: insertId
   type: STRING
   mode: NULLABLE
-  description: A unique identifier for the log entry. Logging considers other log
-    entries in the same project, with the same `timestamp`, and with the same `insertId`
-    to be duplicates which are removed in a single query result.
 - name: httpRequest
   type: RECORD
   mode: NULLABLE
-  description: Information about the HTTP request associated with this log entry,
-    if applicable.
   fields:
   - name: requestMethod
     type: STRING
     mode: NULLABLE
-    description: 'The request method. Examples: "GET", "HEAD", "PUT", "POST".'
   - name: requestUrl
     type: STRING
     mode: NULLABLE
-    description: The scheme (http, https), the host name, the path and the query portion
-      of the URL that was requested.
   - name: requestSize
     type: INTEGER
     mode: NULLABLE
-    description: The size of the HTTP request message in bytes, including the request
-      headers and the request body.
   - name: status
     type: INTEGER
     mode: NULLABLE
-    description: 'The response code indicating the status of response. Examples: 200,
-      404.'
   - name: responseSize
     type: INTEGER
     mode: NULLABLE
-    description: The size of the HTTP response message sent back to the client, in
-      bytes.
   - name: userAgent
     type: STRING
     mode: NULLABLE
-    description: The user agent sent by the client.
   - name: remoteIp
     type: STRING
     mode: NULLABLE
-    description: The IP address (IPv4 or IPv6) of the client that issued the HTTP
-      request.
   - name: serverIp
     type: STRING
     mode: NULLABLE
-    description: The IP address (IPv4 or IPv6) of the origin server that the request
-      was sent to.
   - name: referer
     type: STRING
     mode: NULLABLE
-    description: The referer URL of the request, as defined in HTTP/1.1 Header Field
-      Definitions.
   - name: cacheLookup
     type: BOOLEAN
     mode: NULLABLE
-    description: Whether or not a cache lookup was attempted.
   - name: cacheHit
     type: BOOLEAN
     mode: NULLABLE
-    description: Whether or not an entity was served from cache (with or without validation).
   - name: cacheValidatedWithOriginServer
     type: BOOLEAN
     mode: NULLABLE
-    description: Whether or not the response was validated with the origin server
-      before being served from cache. This field is only meaningful if `cacheHit`
-      is True.
   - name: cacheFillBytes
     type: INTEGER
     mode: NULLABLE
-    description: The number of HTTP response bytes inserted into cache. Set only when
-      a cache fill was attempted.
   - name: protocol
     type: STRING
     mode: NULLABLE
-    description: 'Protocol used for the request. Examples: "HTTP/1.1", "HTTP/2".'
 - name: labels
   type: RECORD
   mode: NULLABLE
-  description: A map of key, value pairs that provides additional information about
-    the log entry.
   fields:
   - name: stack
     type: STRING
@@ -222,79 +182,51 @@
 - name: operation
   type: RECORD
   mode: NULLABLE
-  description: Information about an operation associated with the log entry, if applicable.
   fields:
   - name: id
     type: STRING
     mode: NULLABLE
-    description: An arbitrary operation identifier. Log entries with the same identifier
-      are assumed to be part of the same operation.
   - name: producer
     type: STRING
     mode: NULLABLE
-    description: An arbitrary producer identifier. The combination of `id` and `producer`
-      must be globally unique.
   - name: first
     type: BOOLEAN
     mode: NULLABLE
-    description: Set this to True if this is the first log entry in the operation.
   - name: last
     type: BOOLEAN
     mode: NULLABLE
-    description: Set this to True if this is the last log entry in the operation.
 - name: trace
   type: STRING
   mode: NULLABLE
-  description: The trace ID being written to Cloud Trace in association with this
-    log entry.
 - name: spanId
   type: STRING
   mode: NULLABLE
-  description: The ID of the Cloud Trace span associated with the current operation
-    in which the log is being written.
 - name: traceSampled
   type: BOOLEAN
   mode: NULLABLE
-  description: The sampling decision of the span associated with the log entry at
-    the time the log entry was created.
 - name: sourceLocation
   type: RECORD
   mode: NULLABLE
-  description: Source code location information associated with the log entry, if
-    any.
   fields:
   - name: file
     type: STRING
     mode: NULLABLE
-    description: Source file name. Depending on the runtime environment, this might
-      be a simple name or a fully-qualified name.
   - name: line
     type: INTEGER
     mode: NULLABLE
-    description: Line within the source file. 1-based; 0 indicates no line number
-      available.
   - name: function
     type: STRING
     mode: NULLABLE
-    description: Human-readable name of the function or method being invoked, with
-      optional context such as the class or package name.
 - name: split
   type: RECORD
   mode: NULLABLE
-  description: Information indicating this LogEntry is part of a sequence of multiple
-    log entries split from a single LogEntry.
   fields:
   - name: uid
     type: STRING
     mode: NULLABLE
-    description: A globally unique identifier for all log entries in a sequence of
-      split log entries.
   - name: index
     type: INTEGER
     mode: NULLABLE
-    description: The index of this LogEntry in the sequence of split log entries.
   - name: totalSplits
     type: INTEGER
     mode: NULLABLE
-    description: The total number of log entries that the original LogEntry was split
-      into.
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/firefox_accounts_derived/docker_fxa_admin_server_sanitized_v2/schema.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/firefox_accounts_derived/docker_fxa_admin_server_sanitized_v2/schema.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/firefox_accounts_derived/docker_fxa_admin_server_sanitized_v2/schema.yaml	2026-05-22 22:03:46.930605527 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/firefox_accounts_derived/docker_fxa_admin_server_sanitized_v2/schema.yaml	2026-05-22 22:03:43.002607705 +0000
@@ -5,17 +5,13 @@
 - name: logName
   type: STRING
   mode: NULLABLE
-  description: The resource name of the log to which this log entry belongs.
 - name: resource
   type: RECORD
   mode: NULLABLE
-  description: The monitored resource that produced this log entry.
   fields:
   - name: type
     type: STRING
     mode: NULLABLE
-    description: The monitored resource type. For example, the type of a Compute Engine
-      VM instance is `gce_instance`.
   - name: labels
     type: RECORD
     mode: NULLABLE
@@ -41,12 +37,9 @@
 - name: textPayload
   type: STRING
   mode: NULLABLE
-  description: The log entry payload, represented as a Unicode string (UTF-8).
 - name: jsonPayload
   type: RECORD
   mode: NULLABLE
-  description: The log entry payload, represented as a structure that is expressed
-    as a JSON object.
   fields:
   - name: log_type
     type: STRING
@@ -619,94 +612,61 @@
 - name: receiveTimestamp
   type: TIMESTAMP
   mode: NULLABLE
-  description: The time the log entry was received by Logging.
 - name: severity
   type: STRING
   mode: NULLABLE
-  description: The severity of the log entry. The default value is `LogSeverity.DEFAULT`.
 - name: insertId
   type: STRING
   mode: NULLABLE
-  description: A unique identifier for the log entry. Logging considers other log
-    entries in the same project, with the same `timestamp`, and with the same `insertId`
-    to be duplicates which are removed in a single query result.
 - name: httpRequest
   type: RECORD
   mode: NULLABLE
-  description: Information about the HTTP request associated with this log entry,
-    if applicable.
   fields:
   - name: requestMethod
     type: STRING
     mode: NULLABLE
-    description: 'The request method. Examples: "GET", "HEAD", "PUT", "POST".'
   - name: requestUrl
     type: STRING
     mode: NULLABLE
-    description: The scheme (http, https), the host name, the path and the query portion
-      of the URL that was requested.
   - name: requestSize
     type: INTEGER
     mode: NULLABLE
-    description: The size of the HTTP request message in bytes, including the request
-      headers and the request body.
   - name: status
     type: INTEGER
     mode: NULLABLE
-    description: 'The response code indicating the status of response. Examples: 200,
-      404.'
   - name: responseSize
     type: INTEGER
     mode: NULLABLE
-    description: The size of the HTTP response message sent back to the client, in
-      bytes.
   - name: userAgent
     type: STRING
     mode: NULLABLE
-    description: The user agent sent by the client.
   - name: remoteIp
     type: STRING
     mode: NULLABLE
-    description: The IP address (IPv4 or IPv6) of the client that issued the HTTP
-      request.
   - name: serverIp
     type: STRING
     mode: NULLABLE
-    description: The IP address (IPv4 or IPv6) of the origin server that the request
-      was sent to.
   - name: referer
     type: STRING
     mode: NULLABLE
-    description: The referer URL of the request, as defined in HTTP/1.1 Header Field
-      Definitions.
   - name: cacheLookup
     type: BOOLEAN
     mode: NULLABLE
-    description: Whether or not a cache lookup was attempted.
   - name: cacheHit
     type: BOOLEAN
     mode: NULLABLE
-    description: Whether or not an entity was served from cache (with or without validation).
   - name: cacheValidatedWithOriginServer
     type: BOOLEAN
     mode: NULLABLE
-    description: Whether or not the response was validated with the origin server
-      before being served from cache. This field is only meaningful if `cacheHit`
-      is True.
   - name: cacheFillBytes
     type: INTEGER
     mode: NULLABLE
-    description: The number of HTTP response bytes inserted into cache. Set only when
-      a cache fill was attempted.
   - name: protocol
     type: STRING
     mode: NULLABLE
-    description: 'Protocol used for the request. Examples: "HTTP/1.1", "HTTP/2".'
 - name: labels
   type: RECORD
   mode: NULLABLE
-  description: A map of key, value pairs that provides additional information about
-    the log entry.
   fields:
   - name: k8s_pod_app_kubernetes_io_component
     type: STRING
@@ -756,92 +716,61 @@
 - name: operation
   type: RECORD
   mode: NULLABLE
-  description: Information about an operation associated with the log entry, if applicable.
   fields:
   - name: id
     type: STRING
     mode: NULLABLE
-    description: An arbitrary operation identifier. Log entries with the same identifier
-      are assumed to be part of the same operation.
   - name: producer
     type: STRING
     mode: NULLABLE
-    description: An arbitrary producer identifier. The combination of `id` and `producer`
-      must be globally unique.
   - name: first
     type: BOOLEAN
     mode: NULLABLE
-    description: Set this to True if this is the first log entry in the operation.
   - name: last
     type: BOOLEAN
     mode: NULLABLE
-    description: Set this to True if this is the last log entry in the operation.
 - name: trace
   type: STRING
   mode: NULLABLE
-  description: The trace ID being written to Cloud Trace in association with this
-    log entry.
 - name: spanId
   type: STRING
   mode: NULLABLE
-  description: The ID of the Cloud Trace span associated with the current operation
-    in which the log is being written.
 - name: traceSampled
   type: BOOLEAN
   mode: NULLABLE
-  description: The sampling decision of the span associated with the log entry at
-    the time the log entry was created.
 - name: sourceLocation
   type: RECORD
   mode: NULLABLE
-  description: Source code location information associated with the log entry, if
-    any.
   fields:
   - name: file
     type: STRING
     mode: NULLABLE
-    description: Source file name. Depending on the runtime environment, this might
-      be a simple name or a fully-qualified name.
   - name: line
     type: INTEGER
     mode: NULLABLE
-    description: Line within the source file. 1-based; 0 indicates no line number
-      available.
   - name: function
     type: STRING
     mode: NULLABLE
-    description: Human-readable name of the function or method being invoked, with
-      optional context such as the class or package name.
 - name: split
   type: RECORD
   mode: NULLABLE
-  description: Information indicating this LogEntry is part of a sequence of multiple
-    log entries split from a single LogEntry.
   fields:
   - name: uid
     type: STRING
     mode: NULLABLE
-    description: A globally unique identifier for all log entries in a sequence of
-      split log entries.
   - name: index
     type: INTEGER
     mode: NULLABLE
-    description: The index of this LogEntry in the sequence of split log entries.
   - name: totalSplits
     type: INTEGER
     mode: NULLABLE
-    description: The total number of log entries that the original LogEntry was split
-      into.
 - name: errorGroups
   type: RECORD
   mode: REPEATED
-  description: The Error Reporting error groups associated with this LogEntry.
   fields:
   - name: id
     type: STRING
     mode: NULLABLE
-    description: The id is a unique identifier for a particular error group; it is
-      the last part of the error group resource name.
 - name: apphub
   type: RECORD
   mode: NULLABLE
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/firefox_accounts_derived/docker_fxa_customs_sanitized_v1/schema.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/firefox_accounts_derived/docker_fxa_customs_sanitized_v1/schema.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/firefox_accounts_derived/docker_fxa_customs_sanitized_v1/schema.yaml	2026-05-22 22:03:46.930605527 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/firefox_accounts_derived/docker_fxa_customs_sanitized_v1/schema.yaml	2026-05-22 22:03:43.002607705 +0000
@@ -5,17 +5,13 @@
 - name: logName
   type: STRING
   mode: NULLABLE
-  description: The resource name of the log to which this log entry belongs.
 - name: resource
   type: RECORD
   mode: NULLABLE
-  description: The monitored resource that produced this log entry.
   fields:
   - name: type
     type: STRING
     mode: NULLABLE
-    description: The monitored resource type. For example, the type of a Compute Engine
-      VM instance is `gce_instance`.
   - name: labels
     type: RECORD
     mode: NULLABLE
@@ -32,12 +28,9 @@
 - name: textPayload
   type: STRING
   mode: NULLABLE
-  description: The log entry payload, represented as a Unicode string (UTF-8).
 - name: jsonPayload
   type: RECORD
   mode: NULLABLE
-  description: The log entry payload, represented as a structure that is expressed
-    as a JSON object.
   fields:
   - name: name
     type: STRING
@@ -479,94 +472,61 @@
 - name: receiveTimestamp
   type: TIMESTAMP
   mode: NULLABLE
-  description: The time the log entry was received by Logging.
 - name: severity
   type: STRING
   mode: NULLABLE
-  description: The severity of the log entry. The default value is `LogSeverity.DEFAULT`.
 - name: insertId
   type: STRING
   mode: NULLABLE
-  description: A unique identifier for the log entry. Logging considers other log
-    entries in the same project, with the same `timestamp`, and with the same `insertId`
-    to be duplicates which are removed in a single query result.
 - name: httpRequest
   type: RECORD
   mode: NULLABLE
-  description: Information about the HTTP request associated with this log entry,
-    if applicable.
   fields:
   - name: requestMethod
     type: STRING
     mode: NULLABLE
-    description: 'The request method. Examples: "GET", "HEAD", "PUT", "POST".'
   - name: requestUrl
     type: STRING
     mode: NULLABLE
-    description: The scheme (http, https), the host name, the path and the query portion
-      of the URL that was requested.
   - name: requestSize
     type: INTEGER
     mode: NULLABLE
-    description: The size of the HTTP request message in bytes, including the request
-      headers and the request body.
   - name: status
     type: INTEGER
     mode: NULLABLE
-    description: 'The response code indicating the status of response. Examples: 200,
-      404.'
   - name: responseSize
     type: INTEGER
     mode: NULLABLE
-    description: The size of the HTTP response message sent back to the client, in
-      bytes.
   - name: userAgent
     type: STRING
     mode: NULLABLE
-    description: The user agent sent by the client.
   - name: remoteIp
     type: STRING
     mode: NULLABLE
-    description: The IP address (IPv4 or IPv6) of the client that issued the HTTP
-      request.
   - name: serverIp
     type: STRING
     mode: NULLABLE
-    description: The IP address (IPv4 or IPv6) of the origin server that the request
-      was sent to.
   - name: referer
     type: STRING
     mode: NULLABLE
-    description: The referer URL of the request, as defined in HTTP/1.1 Header Field
-      Definitions.
   - name: cacheLookup
     type: BOOLEAN
     mode: NULLABLE
-    description: Whether or not a cache lookup was attempted.
   - name: cacheHit
     type: BOOLEAN
     mode: NULLABLE
-    description: Whether or not an entity was served from cache (with or without validation).
   - name: cacheValidatedWithOriginServer
     type: BOOLEAN
     mode: NULLABLE
-    description: Whether or not the response was validated with the origin server
-      before being served from cache. This field is only meaningful if `cacheHit`
-      is True.
   - name: cacheFillBytes
     type: INTEGER
     mode: NULLABLE
-    description: The number of HTTP response bytes inserted into cache. Set only when
-      a cache fill was attempted.
   - name: protocol
     type: STRING
     mode: NULLABLE
-    description: 'Protocol used for the request. Examples: "HTTP/1.1", "HTTP/2".'
 - name: labels
   type: RECORD
   mode: NULLABLE
-  description: A map of key, value pairs that provides additional information about
-    the log entry.
   fields:
   - name: application
     type: STRING
@@ -586,79 +546,51 @@
 - name: operation
   type: RECORD
   mode: NULLABLE
-  description: Information about an operation associated with the log entry, if applicable.
   fields:
   - name: id
     type: STRING
     mode: NULLABLE
-    description: An arbitrary operation identifier. Log entries with the same identifier
-      are assumed to be part of the same operation.
   - name: producer
     type: STRING
     mode: NULLABLE
-    description: An arbitrary producer identifier. The combination of `id` and `producer`
-      must be globally unique.
   - name: first
     type: BOOLEAN
     mode: NULLABLE
-    description: Set this to True if this is the first log entry in the operation.
   - name: last
     type: BOOLEAN
     mode: NULLABLE
-    description: Set this to True if this is the last log entry in the operation.
 - name: trace
   type: STRING
   mode: NULLABLE
-  description: The trace ID being written to Cloud Trace in association with this
-    log entry.
 - name: spanId
   type: STRING
   mode: NULLABLE
-  description: The ID of the Cloud Trace span associated with the current operation
-    in which the log is being written.
 - name: traceSampled
   type: BOOLEAN
   mode: NULLABLE
-  description: The sampling decision of the span associated with the log entry at
-    the time the log entry was created.
 - name: sourceLocation
   type: RECORD
   mode: NULLABLE
-  description: Source code location information associated with the log entry, if
-    any.
   fields:
   - name: file
     type: STRING
     mode: NULLABLE
-    description: Source file name. Depending on the runtime environment, this might
-      be a simple name or a fully-qualified name.
   - name: line
     type: INTEGER
     mode: NULLABLE
-    description: Line within the source file. 1-based; 0 indicates no line number
-      available.
   - name: function
     type: STRING
     mode: NULLABLE
-    description: Human-readable name of the function or method being invoked, with
-      optional context such as the class or package name.
 - name: split
   type: RECORD
   mode: NULLABLE
-  description: Information indicating this LogEntry is part of a sequence of multiple
-    log entries split from a single LogEntry.
   fields:
   - name: uid
     type: STRING
     mode: NULLABLE
-    description: A globally unique identifier for all log entries in a sequence of
-      split log entries.
   - name: index
     type: INTEGER
     mode: NULLABLE
-    description: The index of this LogEntry in the sequence of split log entries.
   - name: totalSplits
     type: INTEGER
     mode: NULLABLE
-    description: The total number of log entries that the original LogEntry was split
-      into.
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/firefox_accounts_derived/docker_fxa_customs_sanitized_v2/schema.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/firefox_accounts_derived/docker_fxa_customs_sanitized_v2/schema.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/firefox_accounts_derived/docker_fxa_customs_sanitized_v2/schema.yaml	2026-05-22 22:03:46.939605530 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/firefox_accounts_derived/docker_fxa_customs_sanitized_v2/schema.yaml	2026-05-22 22:03:43.002607705 +0000
@@ -5,17 +5,13 @@
 - name: logName
   type: STRING
   mode: NULLABLE
-  description: The resource name of the log to which this log entry belongs.
 - name: resource
   type: RECORD
   mode: NULLABLE
-  description: The monitored resource that produced this log entry.
   fields:
   - name: type
     type: STRING
     mode: NULLABLE
-    description: The monitored resource type. For example, the type of a Compute Engine
-      VM instance is `gce_instance`.
   - name: labels
     type: RECORD
     mode: NULLABLE
@@ -41,12 +37,9 @@
 - name: textPayload
   type: STRING
   mode: NULLABLE
-  description: The log entry payload, represented as a Unicode string (UTF-8).
 - name: jsonPayload
   type: RECORD
   mode: NULLABLE
-  description: The log entry payload, represented as a structure that is expressed
-    as a JSON object.
   fields:
   - name: type
     type: STRING
@@ -1014,94 +1007,61 @@
 - name: receiveTimestamp
   type: TIMESTAMP
   mode: NULLABLE
-  description: The time the log entry was received by Logging.
 - name: severity
   type: STRING
   mode: NULLABLE
-  description: The severity of the log entry. The default value is `LogSeverity.DEFAULT`.
 - name: insertId
   type: STRING
   mode: NULLABLE
-  description: A unique identifier for the log entry. Logging considers other log
-    entries in the same project, with the same `timestamp`, and with the same `insertId`
-    to be duplicates which are removed in a single query result.
 - name: httpRequest
   type: RECORD
   mode: NULLABLE
-  description: Information about the HTTP request associated with this log entry,
-    if applicable.
   fields:
   - name: requestMethod
     type: STRING
     mode: NULLABLE
-    description: 'The request method. Examples: "GET", "HEAD", "PUT", "PO

⚠️ Only part of the diff is displayed.

Link to full diff

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant