Skip to content

feat(migrate-statsig): Statsig→Confidence migration — Phase 2: code transformation#25

Open
fabriziodemaria wants to merge 1 commit into
mainfrom
statsig-phase2-pr
Open

feat(migrate-statsig): Statsig→Confidence migration — Phase 2: code transformation#25
fabriziodemaria wants to merge 1 commit into
mainfrom
statsig-phase2-pr

Conversation

@fabriziodemaria

@fabriziodemaria fabriziodemaria commented Jun 15, 2026

Copy link
Copy Markdown
Member

Phase 2 of the Statsig→Confidence migration. Phase 1 (#23) is merged, rebased on main.

Scope: the skill only — adds the plan code workflow to migrate-statsig. The example apps used to validate it are intentionally not committed to keep this PR focused; the findings they produced are baked into SKILL.md.

Summary

Adds Phase 2 — code transformation (/confidence:migrate-statsig plan code): transform Statsig SDK usage into the Confidence OpenFeature SDK, one flag = one PR. Registers it in CLAUDE.md / README.md / the command. Targets the Confidence local-resolve providers from spotify/confidence-resolver (JS, Java, Python, Go, Rust) plus the React local-resolve hooks.

How these migrations were tested

The skill's mappings were driven and checked against the real Confidence providers + three real statsig-io/samples apps (not toy fixtures):

App SDK Validation
pythontodo Statsig Python Full round-trip — migrated → created the demo's flags in Confidence via the MCP → resolved live (sample-feature-gatetrue, warning-banner{title:"Big Sale", dismissible:false} for a US user)
node-express legacy statsig-node (CommonJS) migrated → node --check + tsc against the real @spotify-confidence/... + @openfeature/server-sdk
Spring todo Statsig Java (*Async) migrated → mvn compile (BUILD SUCCESS) against the real com.spotify.confidence:openfeature-provider-local

So: every migration was compiled/typechecked against the real Confidence packages, and one (Python) was run end-to-end against a live Confidence project. Per-language reference fixtures (JS/Java/Python compiled; Go/Rust doc-verified) were also used during development.

Findings encoded in the skill

  • Set the Phase 1 entity field (e.g. user_id) in the eval context, not just targetingKey — else every flag resolves to DEFAULT (caught by the live resolve).
  • Python has a local-resolve provider (confidence-openfeature-provider, alpha) → Python migrates in-process, not remote.
  • Sync/async follows the target SDK — JS reads are async (await); Java/Go/Python synchronous → drop Statsig *Async Future/.get().
  • Object reads surface floats (Python) and a dev.openfeature.sdk.Value (Java → asStructure().asObjectMap()).
  • CommonJS → ESM — the Confidence JS provider is ESM-only.
  • log_event / logEvent is BLOCKED — no Confidence event-logging API; leave existing analytics in place.
  • private_attributes are unlogged in Statsig but logged in Confidence → surface before moving into the context.
  • Materialized segments / sticky assignments need a provider materialization store or they silently resolve to DEFAULT.
  • *Sync/*Async/legacy spellings and getLayer → experiment-flag mapping handled.

@fabriziodemaria fabriziodemaria changed the base branch from statsig to main June 15, 2026 09:18
@fabriziodemaria fabriziodemaria marked this pull request as ready for review June 15, 2026 09:19
Adds the `plan code` workflow to the migrate-statsig skill: transforming
Statsig SDK usage (checkGate/getConfig/getExperiment/getLayer, React hooks,
*Sync/*Async/legacy spellings) into the Confidence OpenFeature SDK, one flag
= one PR. Registers it in CLAUDE.md / README.md / the command.

The skill encodes findings validated against the real Confidence local-resolve
providers (spotify/confidence-resolver) and three real statsig-io/samples
demos (node-express, pythontodo, a Spring app) — including one full demo
round-trip (migrate → create flags via MCP → resolve live):

- Set the Phase 1 ENTITY FIELD in the eval context (not just targetingKey),
  else everything resolves to DEFAULT.
- Python has a local-resolve provider now (in-process, not remote).
- Sync/async shape follows the TARGET SDK (JS await; Java/Go/Python sync;
  drop Statsig *Async Future/.get()).
- Object reads: floats in Python, dev.openfeature.sdk.Value in Java.
- CommonJS apps must convert to ESM (provider is ESM-only).
- log_event/logEvent is BLOCKED (no Confidence event-logging API).
- private_attributes change privacy when moved into the (logged) context.
- Materialized segments / sticky assignments need a provider materialization
  store, or they silently resolve to DEFAULT.

Example apps used for validation are kept out of the PR to stay focused on
the skill.

Co-authored-by: Cursor <cursoragent@cursor.com>
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