This document describes the migration plan for transitioning from request-attrs UiFlavor to microcontext ClientFlavor as the source of truth for client/UI flavor identification.
Two separate enum definitions exist for client flavors:
| Library | Enum | Package | Location |
|---|---|---|---|
| request-attrs | UiFlavor |
com.netflix.request.protogen |
request-attrs-api/src/main/proto/com/netflix/request/ui_flavor.proto |
| microcontext | ClientFlavor |
netflix.context.client.flavor |
microcontext-model/src/main/proto/netflix/context/client/flavor/flavor.proto |
- Single Source of Truth: Having two enum definitions leads to drift and maintenance burden
- Microcontext is the Standard: Microcontext is the canonical context propagation library at Netflix
- Deprecation Path: request-attrs flavor support can be gradually deprecated
Conversions are performed by name (not numeric value), ensuring compatibility regardless of proto index differences.
request-attrs UiFlavor |
microcontext ClientFlavor |
Notes |
|---|---|---|
UNKNOWN_UI_FLAVOR |
UNSPECIFIED |
Default/unknown |
AKIRA |
AKIRA |
Web |
ANDROID |
ANDROID |
Android mobile |
ARGO |
ARGO |
iOS mobile |
ATV_FUJI |
ATV_FUJI |
Apple TV 2 & 3 |
ATV_HOPPER |
ATV_HOPPER |
Apple TV 2015 |
DARWIN |
DARWIN |
TV platforms |
IOS_LEGACY |
IOS_LEGACY |
Legacy iOS |
TV_OTHER |
TV_OTHER |
Other TV devices |
WINDOWS_COUGAR |
WINDOWS_COUGAR |
Windows Phone (deprecated) |
WINDOWS_GOTHAM |
WINDOWS_GOTHAM |
Windows 8 (deprecated) |
WINDOWS_PX |
WINDOWS_PX |
Windows 10 (deprecated) |
WINDOWS_WILDCAT |
WINDOWS_WILDCAT |
Windows Phone 8.1 (deprecated) |
ECLIPSE |
ECLIPSE |
TV UI |
ATV_ECLIPSE |
ATV_ECLIPSE |
Apple TV Eclipse |
- Name-based conversion: All conversions use enum names, not numeric proto values
- FAKIRA: Microcontext-only value that maps to
AKIRA(web) when converting toUiFlavor - Microcontext-only values: The following only exist in
ClientFlavorand map toUNKNOWN_UI_FLAVOR:BUTTERFLY(Native iOS)TREX(Native Android)DET(Device Experience Tools)IOS_NGP,ANDROID_NGP,IOS_NGC(Netflix Games Platform)
Decision: The following ClientFlavor values will NOT exist in request-attrs UiFlavor:
BUTTERFLY(Native iOS)TREX(Native Android)DET(Device Experience Tools)IOS_NGP(Netflix Games Platform SDK - iOS)ANDROID_NGP(Netflix Games Platform SDK - Android)IOS_NGC(Netflix Games Controller - iOS)
Rationale:
-
request-attrs is being deprecated - Adding new values to a deprecated enum increases tech debt and extends its lifecycle unnecessarily.
-
These clients are newer - They launched after microcontext became the standard. Services handling these clients should use microcontext directly.
-
Encourages migration - Keeping these values microcontext-only creates a natural forcing function for teams to migrate to
ClientFlavor. -
Minimal impact - Legacy code using
UiFlavorwill receiveUNKNOWN_UI_FLAVORfor these clients, which is acceptable fallback behavior.
Conversion behavior:
ClientFlavor.BUTTERFLY → UiFlavor.UNKNOWN_UI_FLAVOR
ClientFlavor.TREX → UiFlavor.UNKNOWN_UI_FLAVOR
ClientFlavor.DET → UiFlavor.UNKNOWN_UI_FLAVOR
ClientFlavor.IOS_NGP → UiFlavor.UNKNOWN_UI_FLAVOR
ClientFlavor.ANDROID_NGP → UiFlavor.UNKNOWN_UI_FLAVOR
ClientFlavor.IOS_NGC → UiFlavor.UNKNOWN_UI_FLAVOR
Any code that needs to handle these clients specifically must migrate to use ClientFlavor directly.
Based on Sourcegraph analysis, the following repositories import com.netflix.request.protogen.UiFlavor:
| Repository | Phase 4: Migration PR | Phase 5: Cleanup PR |
|---|---|---|
| corp/algo | — | — |
| corp/dna-gusto | — | — |
| corp/ec-dynecom | — | — |
| corp/edge-api-next | - | — |
| corp/edge-server | PR #28694 | — |
| corp/eveng-evidence-control-layer | — | — |
| corp/eveng-text-evidence | — | — |
| corp/gps-cgl | — | — |
| corp/gps-gps | — | — |
| corp/gps-gps-page-fallback | — | — |
| corp/gps-gps-page-router | PR #1109 | — |
| corp/gps-gpsintegrationtest | — | — |
| corp/gps-group-service-2 | — | — |
| corp/recsys-sectiongenerator | — | — |
Status: Complete
- Add
WINDOWS_COUGARto microcontextClientFlavorenum (value 22, deprecated) - Update
ClientResolvers.clientCategory()to mapWINDOWS_COUGAR→ClientCategory.WIN - Decision: Certain flavors (
BUTTERFLY,TREX,DET,IOS_NGP,ANDROID_NGP,IOS_NGC) will remain microcontext-only (see Microcontext-Only Flavors)
Status: Complete — PR #618, PR #620
Goal: Allow request-attrs to use microcontext ClientFlavor as the source of truth
- Add microcontext dependency to request-attrs
- Create
ClientFlavorsutility class with bidirectional conversion - Add
withClientFlavor(ClientFlavor)toRequestAttributes.Builder - Add
getClientFlavor()toRequestAttributes - Deprecate
withUIFlavor(UiFlavor)andgetUIFlavor() - Add
setClientFlavor()andgetClientFlavor()toRequestAttributesProto - Deprecate
setUiFlavorEnum()andgetUiFlavorEnum()in proto
Status: Complete — PR #619, PR #624
- Mark
UiFlavorproto enum as deprecated - Mark
RequestAttributes.getUIFlavor()as@Deprecated - Add Javadoc pointing to
ClientFlavoras replacement - Update consumer documentation
- Remove
BUTTERFLY,TREX,DETfromUiFlavor(now microcontext-only)
For each affected repository, follow the Client Migration Guide:
- Upgrade to
request-attrs0.8.5 or later - Update imports from
UiFlavortoClientFlavor - Replace
withUIFlavor()calls withwithClientFlavor() - Replace
getUIFlavor()calls withgetClientFlavor() - Replace
RequestAttributesProto.setUiFlavorEnum()withsetClientFlavor() - Replace
RequestAttributesProto.getUiFlavorEnum()withgetClientFlavor() - Replace
UiFlavor.name()/.toString()withClientFlavors.toUiFlavorName() - Update enum comparisons (
UNKNOWN_UI_FLAVOR→UNSPECIFIED) - Test thoroughly
Sample Prompt: implement the Client Migration as indicated in https://github.netflix.net/corp/dna-microcontext/blob/master/mkdocs/docs/migrations/flavor_migration.md in this codebase
Note: Consumers can migrate at their own pace. The request-attrs implementation uses ClientFlavor as internal storage with conversion at the API boundary, so old code using getUIFlavor() and new code using getClientFlavor() interoperate seamlessly:
// Internal storage: ClientFlavor clientFlavor
// New API (preferred) - direct access
withClientFlavor(ClientFlavor f) → clientFlavor = f
getClientFlavor() → return clientFlavor
// Old API (deprecated) - converts at boundary
withUIFlavor(UiFlavor f) → clientFlavor = ClientFlavors.fromUiFlavor(f)
getUIFlavor() → return ClientFlavors.toUiFlavor(clientFlavor)
- Remove deprecated
UiFlavorfrom request-attrs - Remove conversion utilities
- Archive migration documentation
WINDOWS_COUGARadded toflavor.protoat value 22 with[deprecated = true]ClientResolvers.clientCategory()updated to handleWINDOWS_COUGAR→WIN
None additional in microcontext - the enum is now at parity.
Added ClientFlavors.java in request-attrs-api (com.netflix.request package) with:
fromName(String)- Parse ClientFlavor from string name (case-insensitive)fromNameOrDefault(String)- Parse with fallback to UNSPECIFIEDfromUiFlavor(UiFlavor)- Convert UiFlavor → ClientFlavortoUiFlavor(ClientFlavor)- Convert ClientFlavor → UiFlavortoUiFlavorName(ClientFlavor)- Get the equivalent UiFlavor string name without importing UiFlavor
This utility is in the API module so it's available to all consumers without requiring additional dependencies.
New methods (preferred):
// Builder
Builder withClientFlavor(ClientFlavor flavor);
// Interface
default ClientFlavor getClientFlavor() {
return ClientFlavor.UNSPECIFIED;
}Deprecated methods:
// Builder
@Deprecated
Builder withUIFlavor(UiFlavor flavor);
// Interface
@Deprecated
default UiFlavor getUIFlavor() {
return null;
}For consumers of request-attrs, follow these steps to migrate to ClientFlavor.
Upgrade to request-attrs 0.8.1 or later:
// Before
import com.netflix.request.protogen.UiFlavor;
// After
import netflix.context.client.flavor.ClientFlavor;// Before
RequestAttributes attrs = builder
.withUIFlavor(UiFlavor.AKIRA)
.build();
// After
RequestAttributes attrs = builder
.withClientFlavor(ClientFlavor.AKIRA)
.build();// Before
UiFlavor flavor = requestAttributes.getUIFlavor();
if (flavor == UiFlavor.AKIRA) { ... }
// After
ClientFlavor flavor = requestAttributes.getClientFlavor();
if (flavor == ClientFlavor.AKIRA) { ... }If using RequestAttributesProto directly, follow the standard protobuf migration pattern:
During migration: Set both fields to ensure compatibility with all consumers:
// Transition period: Write BOTH fields
RequestAttributesProto.Builder builder = RequestAttributesProto.newBuilder();
builder.setClientFlavor(ClientFlavor.AKIRA); // New field (preferred)
builder.setUiFlavorEnum(ClientFlavors.toUiFlavor(ClientFlavor.AKIRA)); // Deprecated field (for compatibility)
// Reading: Prefer ClientFlavor, fall back to UiFlavor if needed
ClientFlavor flavor = proto.hasClientFlavor()
? proto.getClientFlavor()
: ClientFlavors.fromUiFlavor(proto.getUiFlavorEnum());Why dual-write? This follows the standard protobuf field migration pattern:
- Introduce new field (
clientFlavor) — Complete - Deprecate old field (
uiFlavorEnum) — Complete - Migrate clients to write both fields — Current phase
- Once all producers write both fields, consumers can switch to reading only
clientFlavor - Once all consumers read only
clientFlavor, producers can stop writinguiFlavorEnum - Remove deprecated field — Future cleanup
After migration is complete (all libraries confirmed to consume clientFlavor):
// Final state: Only write ClientFlavor
RequestAttributesProto.Builder builder = RequestAttributesProto.newBuilder();
builder.setClientFlavor(ClientFlavor.AKIRA);
// Reading: Use ClientFlavor directly
ClientFlavor flavor = proto.getClientFlavor();Note: Do not remove
setUiFlavorEnum()calls until the migration team confirms all downstream consumers have been updated to read fromclientFlavor. Premature removal will break services still reading from the deprecated field.
If your code converts UiFlavor to a string (e.g., .name() or .toString()), use toUiFlavorName() instead:
// Before - requires UiFlavor import
import com.netflix.request.protogen.UiFlavor;
String name = uiFlavor.name();
// After - no UiFlavor import needed
import com.netflix.request.ClientFlavors;
String name = ClientFlavors.toUiFlavorName(clientFlavor);Old (UiFlavor) |
New (ClientFlavor) |
|---|---|
UNKNOWN_UI_FLAVOR |
UNSPECIFIED |
| All other values | Same name |
If your code needs to handle native mobile, DET, or Netflix Games Platform clients, you must use ClientFlavor:
ClientFlavor flavor = requestAttributes.getClientFlavor();
switch (flavor) {
case BUTTERFLY: // Native iOS
case TREX: // Native Android
case DET: // Device Experience Tools
case IOS_NGP: // Netflix Games Platform - iOS
case ANDROID_NGP: // Netflix Games Platform - Android
case IOS_NGC: // Netflix Games Controller - iOS
// Handle these clients specifically
break;
// ...
}These values do not exist in UiFlavor and will appear as UNKNOWN_UI_FLAVOR if using the deprecated API.
Prerequisites: Only perform this step after the migration team confirms:
- All downstream consumers have been updated to read from
clientFlavor - No services are still reading exclusively from
uiFlavorEnum
Once confirmed, remove the deprecated uiFlavorEnum calls:
// Before (dual-write during transition)
RequestAttributesProto.Builder builder = RequestAttributesProto.newBuilder();
builder.setClientFlavor(ClientFlavor.AKIRA);
builder.setUiFlavorEnum(ClientFlavors.toUiFlavor(ClientFlavor.AKIRA)); // Remove this line
// After (final state)
RequestAttributesProto.Builder builder = RequestAttributesProto.newBuilder();
builder.setClientFlavor(ClientFlavor.AKIRA);Also remove any remaining UiFlavor imports:
// Remove this import
import com.netflix.request.protogen.UiFlavor;Checklist before removing dual-write:
- Confirmed with migration team that all consumers read
clientFlavor - Verified no alerts or errors related to missing
uiFlavorEnumin downstream services - Tested in a non-production environment first
During the transition, you can use ClientFlavors for conversion:
import com.netflix.request.ClientFlavors;
// Convert UiFlavor to ClientFlavor
ClientFlavor clientFlavor = ClientFlavors.fromUiFlavor(uiFlavor);
// Convert ClientFlavor to UiFlavor (for legacy code)
UiFlavor legacyFlavor = ClientFlavors.toUiFlavor(clientFlavor);If your code only needs the UiFlavor string name (e.g., for logging, metrics, or passing to legacy APIs that accept strings), use toUiFlavorName() to avoid importing the deprecated UiFlavor enum entirely:
import com.netflix.request.ClientFlavors;
import netflix.context.client.flavor.ClientFlavor;
// Get the equivalent UiFlavor name as a String
String flavorName = ClientFlavors.toUiFlavorName(ClientFlavor.AKIRA); // Returns "AKIRA"
String unknownName = ClientFlavors.toUiFlavorName(ClientFlavor.BUTTERFLY); // Returns "UNKNOWN_UI_FLAVOR"
String nullSafe = ClientFlavors.toUiFlavorName(null); // Returns "UNKNOWN_UI_FLAVOR"This is the preferred approach when you need the string value, as it:
- Avoids importing
UiFlavor- No dependency on the deprecated enum - Handles microcontext-only flavors - Returns
"UNKNOWN_UI_FLAVOR"forBUTTERFLY,TREX,DET, etc. - Is null-safe - Returns
"UNKNOWN_UI_FLAVOR"for null input - Keeps mapping logic centralized - Uses the same conversion rules as
toUiFlavor()
Common use cases:
// Logging
log.info("Processing request for flavor: {}", ClientFlavors.toUiFlavorName(clientFlavor));
// Metrics/dimensions
registry.counter("requests", "flavor", ClientFlavors.toUiFlavorName(clientFlavor));
// Legacy API calls that accept String
legacyService.setFlavor(ClientFlavors.toUiFlavorName(clientFlavor));| Risk | Impact | Mitigation |
|---|---|---|
| Breaking changes in consumers | Medium | Phased rollout with deprecation warnings |
| NGP flavors map to UNKNOWN in UiFlavor | Low | Intentional; forces migration for NGP-aware code |
FAKIRA mapping |
Low | Maps to AKIRA (web) when converting to UiFlavor |
| Phase | Status |
|---|---|
| Phase 1 (Parity) | Complete |
| Phase 2 (Conversion) | Complete (PR #618, PR #620) |
| Phase 3 (Deprecation) | Complete (PR #619, PR #624) |
| Phase 4 (Consumer Migration) | In Progress (see Affected Repositories) |
| Phase 5 (Cleanup) | Not Started |
- Client Applications Spreadsheet
- Microcontext Manuals
- request-attrs Repository
- request-attrs ClientFlavors PR #618
- request-attrs Deprecation PR #619
- request-attrs Proto ClientFlavor PR #620
- request-attrs UiFlavor Cleanup PR #624
- request-attrs toUiFlavorName PR #626
- ClientFlavors.java
- RequestAttributes.java
- Sourcegraph Deep Search:
bf266c60-8c1e-4e67-a609-25970558920e