feat: extend OpenFeature numeric, payload, and reason support - #216
Conversation
|
[Medium risk] Extends OpenFeature flag resolution to handle more data types. The new change appears safe to merge, though the previously reported missing reason metadata on type mismatches remains. Reviews (2) · Last reviewed commit: "docs: explain upstream OpenFeature array..." |
posthog-elixir Compliance ReportDate: 2026-09-25T06:33:47.152904+00:00
|
| Test | Status | Duration |
|---|---|---|
| Format Validation.Event Has Required Fields | ✅ | 609ms |
| Format Validation.Event Has Uuid | ✅ | 610ms |
| Format Validation.Event Has Lib Properties | ✅ | 610ms |
| Format Validation.Distinct Id Is String | ✅ | 610ms |
| Format Validation.Token Is Present | ✅ | 610ms |
| Format Validation.Custom Properties Preserved | ✅ | 610ms |
| Format Validation.Event Has Timestamp | ✅ | 610ms |
| Format Validation.Non Utc Event Timestamp Is Converted To Utc | ❌ | 610ms |
| Retry Behavior.Retries On 503 | ✅ | 5616ms |
| Retry Behavior.Does Not Retry On 400 | ✅ | 2611ms |
| Retry Behavior.Does Not Retry On 401 | ✅ | 2611ms |
| Retry Behavior.Respects Retry After Header | ✅ | 5617ms |
| Retry Behavior.Implements Backoff | ✅ | 15624ms |
| Retry Behavior.Retries On 500 | ✅ | 5616ms |
| Retry Behavior.Retries On 502 | ✅ | 5616ms |
| Retry Behavior.Retries On 504 | ✅ | 5616ms |
| Retry Behavior.Max Retries Respected | ✅ | 15625ms |
| Deduplication.Generates Unique Uuids | ✅ | 623ms |
| Deduplication.Preserves Uuid On Retry | ✅ | 5615ms |
| Deduplication.Preserves Uuid And Timestamp On Retry | ✅ | 10611ms |
| Deduplication.Preserves Uuid And Timestamp On Batch Retry | ✅ | 5618ms |
| Deduplication.No Duplicate Events In Batch | ✅ | 615ms |
| Deduplication.Different Events Have Different Uuids | ✅ | 612ms |
| Compression.Sends Gzip When Enabled | ✅ | 610ms |
| Batch Format.Uses Proper Batch Structure | ✅ | 610ms |
| Batch Format.Flush With No Events Sends Nothing | ✅ | 607ms |
| Batch Format.Multiple Events Batched Together | ✅ | 615ms |
| Error Handling.Does Not Retry On 403 | ✅ | 2612ms |
| Error Handling.Does Not Retry On 413 | ✅ | 2613ms |
| Error Handling.Retries On 408 | ✅ | 5616ms |
Failures
format_validation.non_utc_event_timestamp_is_converted_to_utc
Event 0 field 'timestamp' instant '2026-09-25T06:32:03.085966Z' != expected '2025-01-02T03:04:05Z'
Feature_Flags Tests
View Details
| Test | Status | Duration |
|---|---|---|
| Request Payload.Request With Person Properties Device Id | ✅ | 8ms |
| Request Payload.Flags Request Uses V2 Query Param | ✅ | 7ms |
| Request Payload.Flags Request Hits Flags Path Not Decide | ✅ | 6ms |
| Request Payload.Flags Request Omits Authorization Header | ✅ | 7ms |
| Request Payload.Token In Flags Body Matches Init | ✅ | 7ms |
| Request Payload.Groups Round Trip | ✅ | 6ms |
| Request Payload.Groups Default To Empty Object | ❌ | 7ms |
| Request Payload.Disable Geoip False Propagates As Geoip Disable False | ✅ | 6ms |
| Request Payload.Disable Geoip Omitted Defaults To False | ❌ | 7ms |
| Request Payload.Flag Keys To Evaluate Contains Only Requested Key | ✅ | 7ms |
| Request Lifecycle.No Flags Request On Init Alone | ✅ | 3ms |
| Request Lifecycle.No Flags Request On Normal Capture | ✅ | 609ms |
| Request Lifecycle.Two Flag Calls Produce Two Remote Requests | ✅ | 12ms |
| Request Lifecycle.Mock Response Value Is Returned To Caller | ❌ | 6ms |
| Retry Behavior.Retries Flags On 502 | ❌ | 311ms |
| Retry Behavior.Retries Flags On 504 | ❌ | 311ms |
| Side Effect Events.Get Feature Flag Captures Feature Flag Called Event | ❌ | 609ms |
Failures
request_payload.groups_default_to_empty_object
Field 'groups' not found in /flags request body at path 'groups'. Available keys: ['api_key', 'distinct_id', 'flag_keys_to_evaluate']
request_payload.disable_geoip_omitted_defaults_to_false
Field 'geoip_disable' not found in /flags request body at path 'geoip_disable'. Available keys: ['api_key', 'distinct_id', 'flag_keys_to_evaluate']
request_lifecycle.mock_response_value_is_returned_to_caller
Last action result missing field 'value'. Keys: ['error', 'success']
retry_behavior.retries_flags_on_502
Last action result missing field 'value'. Keys: ['error', 'success']
retry_behavior.retries_flags_on_504
Last action result missing field 'value'. Keys: ['error', 'success']
side_effect_events.get_feature_flag_captures_feature_flag_called_event
Expected 1 events with name '$feature_flag_called', got 0
| # open-feature/elixir-sdk 0.1.3 guards get_map_value/get_map_details defaults | ||
| # with is_map/1 before calling the provider, but does not restrict returned | ||
| # values. Array payloads work with a map default; list defaults need an upstream fix. |
829dbe2
into
posthog/openfeature-provider
* feat: add OpenFeature provider Add PostHog.OpenFeature.Provider for the Elixir OpenFeature SDK, with open_feature as an optional dependency. The provider mirrors the posthog-node OpenFeature provider: targeting_key maps to distinct_id, groups and group_properties map to groups, and other context keys map to person properties. Generated-By: PostHog Desktop Task-Id: 45365cd7-19ef-46e1-8d2a-46d2f484d229 * fix: return the default for disabled flags and update public API snapshot The string, number, and map resolvers now check `enabled: false` before inspecting the variant or payload, so a disabled flag that still carries a remote value resolves to the caller-supplied default. Adds a test for each type. Regenerates public_api.snapshot to include PostHog.OpenFeature.Provider, which the "Compile with warnings as errors" CI job checks. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Generated-By: PostHog Desktop Task-Id: 8167c421-7e51-4669-be55-fc7b39e39d26 * docs: describe disabled-flag resolution after resolver reorder Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Generated-By: PostHog Desktop Task-Id: 8167c421-7e51-4669-be55-fc7b39e39d26 * fix: match Node and Python providers for disabled flags and numeric variants A disabled flag that still carries a variant or payload now resolves to that value with reason `:default`, as the Node and Python providers do. Number resolution accepts `.5`, `-.5`, and `1.`, which JavaScript's Number() and Python's float() accept but Float.parse/1 does not. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Generated-By: PostHog Desktop Task-Id: 8167c421-7e51-4669-be55-fc7b39e39d26 * feat: extend OpenFeature numeric, payload, and reason support (#216) * feat: extend OpenFeature numeric, payload, and reason support * docs: explain upstream OpenFeature array-default limitation * fix: preserve OpenFeature reason metadata on type mismatches * chore: remove redundant OpenFeature follow-up changeset --------- Co-authored-by: Patricio <patricio@posthog.com> Co-authored-by: Manoel Aranda Neto <5731772+marandaneto@users.noreply.github.com> Co-authored-by: Manoel Aranda Neto <marandaneto@gmail.com>
💡 Motivation and Context
Stacked on #214. This PR targets
posthog/openfeature-provider, notmain, so #214 can merge independently. After #214 merges, retarget this follow-up tomain.The cross-provider comparison in #214 identified three additions:
0x10and0Xff. Invalid and signed hexadecimal strings remain type mismatches.%{}), even whenget_map_value/4returns an array. This restriction is documented in the module docs and a code comment besideresolve_map_value/4, and tested through the real client.flag_metadata["posthog_reason"], using the PostHog description, code, or existing string reason. Explicit serverflag_disabledcodes map off results to:disabled. Other off results stay:default. Type-mismatch details retain available reason metadata while preserving the error code and caller default. This uses a stable code rather than Python's description substring check.Error-hook behavior is unchanged and tracked separately in #215. There is no OpenFeature-specific SDK spec.
Related work: PostHog/posthog-python#980 and PostHog/posthog-js#5099.
💚 How did you test it?
mix test: 596 passed, 18 integration tests excluded.mix format --check-formatted,MIX_ENV=test mix compile --warnings-as-errors, andmix credo --strictpassed.origin/posthog/openfeature-providerreported no actionable findings.Checks ran on Elixir 1.20.4 / OTP 29. No live PostHog project was used.
📝 Checklist
If releasing new changes
sampo addto generate a changeset file🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Implemented with Pi using local file editing, shell tests, and the isolated autoreview helper. The user requested a separate follow-up so the initial provider PR can merge without waiting for these additions. The upstream map-default restriction is documented rather than changing the OpenFeature dependency. No shared session link is available.