Replace Statsig with GrowthBook for experimentation#8567
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
b3c59ae to
b2e1d7e
Compare
|
Claude finished @CouchersBot[bot]'s task in 1m 13s —— View job I'll analyze this and get back to you. |
Migration ReviewOne of our most common issues is migrations that don't work with existing Overall Risk: SAFE Files Reviewed
FindingsNo issues found. The migration was renumbered from The change is purely additive — SummaryThe migration is safe to apply against production: a new empty table with no impact on existing data, and the revision chain is linear at |
|
Claude finished @CouchersBot[bot]'s task in 1m 27s —— View job I'll analyze this and get back to you. |
| on_experiment_viewed=on_experiment_viewed, | ||
| ) | ||
| context._growthbook = gb # type: ignore[attr-defined] | ||
| return context._growthbook # type: ignore[attr-defined, no-any-return] |
There was a problem hiding this comment.
Can we add _growthbook as an attribute to CouchersContext, with None as default? Then there will be no need for type ignores
b5dd633 to
f0d4a0d
Compare
|
Claude finished @aapeliv's task in 2m 49s —— View job Migration Safety Review
Overall Risk: HIGH RISK — revision-number collision blocks this migration. This PR's Fix: rebase onto The table itself is fine — Full review posted here, with an inline suggestion on the migration file. |
|
Claude finished @aapeliv's task in 1m 18s —— View job Migration Safety Review
Overall Risk: SAFE — the revision collision is resolved and the migration is purely additive. The migration is now
Full review updated here. |
Swap the backend experimentation framework from Statsig to GrowthBook's sync Python SDK. Drop the unused get_experiment / get_dynamic_config / log_event helpers and the fork-safety boilerplate that was needed for Statsig's threaded internals but not for the sync GrowthBook client.
Adds a generic typed get_feature_value(context, name, default) so callers can read strings, numbers, dicts, and experiment variations - not just boolean gates. Also restores the 'Experimentation is disabled' log line that got trimmed in the initial swap.
The SDK defaults to no timeout, so a slow CDN response could block a worker indefinitely on the periodic refresh. Set http_connect_timeout=1 and http_read_timeout=2 on both the warmup and per-request instances.
Swap @statsig/react-bindings for @growthbook/growthbook-react, slim the experimentation hook surface to useGate + useFeatureValue (matching the backend), and migrate the single donation_amounts consumer. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds a logging.experiment_exposures table populated by GrowthBook's on_experiment_viewed callback. Each row captures one distinct exposure of a user to an experiment, deduped via a sha256 fingerprint over the assignment-relevant fields - so a re-bucketing or weight change produces a new row with its own timestamp, while identical re-evaluations are collapsed via ON CONFLICT DO NOTHING on (user_id, experiment_key, fingerprint). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Drops the sha256 fingerprint column in favour of a plain unique constraint on (user_id, experiment_key, variation_id). We accept that re-bucketings within the same variation aren't separately recorded; `created` and `data` reflect the first exposure for that variation. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The bot-generated 0151 migration referenced the dropped `fingerprint` column. Removing it so CI can regenerate against the current schema. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Owns the feature fetch directly instead of going through the library's feature_repo singleton. A daemon thread refreshes every minute and request threads only ever read the in-memory snapshot - they never block on the CDN and they keep the last known good state on fetch failure. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Points the web frontend (dev/staging/prod) and the dev/staging backend at the gbapi.couchershq.org proxy with their respective SDK keys. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The only frontend experiment - drop the useFeatureValue hook and use the DONATIONS_BOX_VALUES constant directly at all three reference sites. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Declare _growthbook directly on CouchersContext so _get_growthbook no longer needs type: ignore comments. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
34d32aa to
9db8053
Compare
|
Claude finished @aapeliv's task in 1m 30s —— View job Migration ReviewOne of our most common issues is migrations that don't work with existing Overall Risk: SAFE Files Reviewed
FindingsNo issues found. The migration was renumbered from The change is purely additive — SummaryThe migration is safe to apply against production: a new empty table with no impact on existing data, and the revision chain is linear at |
📝 Release NotesThis PR does not need to be included in release notes. Reason: This PR primarily replaces the internal experimentation/feature flag infrastructure from Statsig to GrowthBook. The public API is mostly unchanged and there is no clear new user-facing feature or noticeable UX change described. While it includes some technical improvements, this looks like backend/internal tooling work rather than a major end-user-visible reliability or performance improvement that should go in release notes. 🤖 Bot Debug InformationModel: |
Swaps the backend experimentation framework from Statsig to GrowthBook's sync Python SDK. The public API (
check_gate) is unchanged.statsig-python-core→growthbook>=1.2.0inpyproject.tomlexperimentation.pyrewritten on the syncGrowthBookclient; the sharedfeature_repocache is pre-warmed insetup_experimentation()STATSIG_SERVER_SECRET_KEY/STATSIG_ENVIRONMENTconfig →GROWTHBOOK_API_HOST/GROWTHBOOK_CLIENT_KEY(also updated inbackend.dev.envandconftest.py)get_experiment,get_dynamic_config, andlog_eventhelpers (the last one also collided withcouchers.event_log.log_event)app.py/worker.pywere pared down accordinglytest_statsig_integration→test_growthbook_integrationTesting
make formatis cleanmake mypyreports no new errors (the 17 pre-existing errors are unrelated — protoattachments, abstractAccount.DismissReminder,icsstubs)from couchers.experimentation import check_gate, setup_experimentationimports cleanly with the newgrowthbookdep installedtest_growthbook_integrationgate flips as expected withEXPERIMENTATION_ENABLED=1Backend checklist
developif necessary for linear migration historyFor maintainers
This PR was created with the Couchers PR skill.