Skip to content

feat(nimbus): extend population sizing ETL to support Fenix and iOS mobile - #9824

Merged
yashikakhurana merged 12 commits into
mainfrom
EXP-7366
Sep 9, 2026
Merged

yashikakhurana merged 12 commits into
mainfrom
EXP-7366

Conversation

@yashikakhurana

@yashikakhurana yashikakhurana commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Description

This PR extends the Nimbus pre-launch population sizing ETL to support Fenix and iOS mobile experiments alongside the existing Desktop support. Experiments are grouped by appName from the Experimenter API and queried against their respective BQ targeting tables. Mobile uses hash-based 10% sampling since derived tables have no sample_id column. A platform column is added to BQ and GCS output.

Related Tickets & Documents

Reviewer, please follow this checklist

…obile experiments

Add Fenix and iOS targeting tables, group experiments by appName, use
hash-based 10% sampling for mobile (no sample_id column in derived tables),
and include platform in results written to GCS and BigQuery.
@yashikakhurana yashikakhurana changed the title feat(nimbus): extend population sizing ETL to support Fenix and iOS m… feat(nimbus): extend population sizing ETL to support Fenix and iOS mobile Aug 26, 2026

@github-actions github-actions Bot left a comment

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.

This PR extends the Nimbus pre-launch population sizing ETL from desktop-only to also cover Fenix and iOS: experiments from the Experimenter v8 API are grouped by appName, each group is dry-run validated and queried against its own targeting-context table, and a platform column is added to the BigQuery schema and the GCS payload. Mobile uses hash-based 10% sampling and submission_date-based dedup since the derived tables have no sample_id.

The main thing to resolve before this lands is the dry-run validation probe: require_partition_filter: true on both mobile derived tables makes WHERE FALSE an invalid query, so every Fenix and iOS experiment gets dropped and the new mobile path becomes a silent no-op. The remaining comments are about failure isolation between platforms and keeping the two sampling constants linked.

On the reviewer checklist: the PR title carries the EXP-7366 reference, this isn't a fork, schema.yaml is updated for the new platform field, referenced_tables and dag_name line up (both mobile tables are produced in bqetl_experiments_daily), no backfill.yaml change, and monitoring isn't a restricted namespace.

@scholtzan

This comment has been minimized.

- Add submission_date partition filter to dry-run probe so mobile
  tables with require_partition_filter=true pass validation
- Wrap per-platform loop body in try/except so one platform failure
  does not discard results already accumulated for other platforms
- Use MOD(..., 100) < SAMPLE_ID_MAX for mobile sampling to mirror
  desktop sample_id range and keep both branches linked to the constant
- Replace table+is_mobile params with app_name in build_query and
  _dry_run_sql; derive config from _APP_CONFIG to make mismatches
  unrepresentable
@scholtzan

This comment has been minimized.

@yashikakhurana

Copy link
Copy Markdown
Contributor Author

@mikewilli mikewilli left a comment

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.

I am thinking it might make more sense to separate the ETL for querying the population estimates from the task that joins the various apps and sends results to GCS. Do you think it would fit and make sense to create a per-app table via the templating we have for other experiment monitoring here https://github.com/mozilla/bigquery-etl/blob/main/sql_generators/experiment_monitoring/templates/templating.yaml, and then query the result(s) more straightforwardly here to aggregate and send to GCS and a final view or table to BigQuery?

If you'd rather stick with this approach, see my comments below for standardizing the query for all apps if possible.

…gation

Create nimbus_sizing_clients_{desktop,fenix,ios}_v1 tables that pre-materialise
a 7-day rolling window of deduplicated, 10%-sampled clients per app. The
experiment_population_estimates_v1 query.py now just runs COUNTIF queries
against these pre-built tables and ships results to GCS and BigQuery, with
no inline deduplication, date arithmetic, or is_mobile branching needed.
@scholtzan

This comment has been minimized.

@scholtzan

This comment has been minimized.

…ient tables

Replaces three manually-maintained SQL files with a single Jinja2 template
in sql_generators/nimbus_population_sizing/. The generator renders
nimbus_sizing_clients_{desktop,fenix,ios}_v1 from one template with
conditional blocks for desktop vs mobile differences (client ID field,
sampling method, date column). Running `bqetl generate
nimbus_population_sizing` regenerates all three tables from the single
source of truth.
@yashikakhurana
yashikakhurana requested a review from a team as a code owner September 3, 2026 19:43
…toring generator

Moves the per-app nimbus sizing client pool tables into the existing
experiment_monitoring sql_generator following Mike's suggestion, using
the same pattern as experiment_enrollment_aggregates_v1 with {% if %}
conditional blocks for desktop vs Glean mobile apps.

Changes:
- Extend experiment_monitoring/__init__.py to support destination_project
  per query in per_app: true mode
- Add nimbus_sizing_clients_v1 template to experiment_monitoring/templates/
  with desktop/mobile conditional blocks
- Register nimbus_sizing_clients_v1 in templating.yaml targeting
  moz-fx-data-experiments, skipping all non-sizing apps
- Move generated tables from monitoring.nimbus_sizing_clients_{app}_v1
  to {app}_derived.nimbus_sizing_clients_v1 to match the generator naming
- Remove standalone nimbus_population_sizing generator
- Update query.py table references to new paths
@scholtzan

This comment has been minimized.

@scholtzan

This comment has been minimized.

Generated output from sql_generators is not committed to sql/ — the
template in sql_generators/experiment_monitoring/templates/ is the
source of truth and bqetl generate produces the files at deploy time.
@scholtzan

This comment has been minimized.

@mikewilli mikewilli left a comment

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.

I think we should write these intermediate tables to shared-prod, but otherwise I think this makes sense now.

Comment thread sql_generators/experiment_monitoring/templates/templating.yaml Outdated
…ents

Intermediate client pool tables belong in moz-fx-data-shared-prod
alongside their source data. Only the final GCS/BQ output
(experiment_population_estimates_v1) stays in moz-fx-data-experiments.

@mikewilli mikewilli left a comment

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.

r+wc

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.

I don't think these changes are needed anymore, are they?

…itoring generator

No query currently uses destination_project; revert the __init__.py
change to keep the diff minimal.
@scholtzan

This comment has been minimized.

@scholtzan

Copy link
Copy Markdown
Collaborator

Integration report

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.

3 participants