Skip to content

[AI-FSSDK] [FSSDK-12813] Normalize decision event campaign_id, variation_id, and entity_id#415

Open
jaeopt wants to merge 2 commits into
masterfrom
ai/jaeopt/FSSDK-12813-holdout-event
Open

[AI-FSSDK] [FSSDK-12813] Normalize decision event campaign_id, variation_id, and entity_id#415
jaeopt wants to merge 2 commits into
masterfrom
ai/jaeopt/FSSDK-12813-holdout-event

Conversation

@jaeopt

@jaeopt jaeopt commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Normalize three decision-event fields uniformly across every decision type (experiment, feature test, rollout, holdout) in the event-builder layer so the wire output is byte-equivalent across SDKs for the same input. decisions[].campaign_id and impression events[].entity_id accept any non-empty string (including opaque IDs like "default-12345" or "layer_abc") and fall back to experiment_id only when the value is null or empty string. decisions[].variation_id retains the stricter numeric-string contract and falls back to null for empty / whitespace / non-numeric values. Non-string types are out of scope. Conversion-event entity_id is unchanged. The path never logs, throws, or blocks dispatch.

Changes

  • Added OptimizelySDK/Utils/EventIdNormalizer.cs encapsulating the rules with two validators: IsNonEmptyString (for campaign_id / entity_id) and IsNumericIdString (for variation_id). NormalizeCampaignId falls back to experiment_id only when the input is null or ""; NormalizeVariationId falls back to null when the input is not a non-empty decimal-digit string.
  • Wired the normalizer into EventFactory.CreateVisitor(ImpressionEvent) and the obsolete EventBuilder.GetImpressionParams so both paths stay byte-equivalent. Impression entity_id reuses the normalized campaign_id.
  • Audited existing event-builder tests per FR-011 — happy-path fixtures already use numeric IDs; the rollout case in TestCreateImpressionEventRemovesInvalidAttributesFromPayloadRollout remains correct under the relaxed contract (null LayerId still triggers fallback to empty experiment_id). Unit and integration tests updated for the relaxed campaign_id / entity_id contract: opaque non-empty strings (e.g. "default-12345", "layer_abc", "variation_a") now pass through unchanged; only null and "" trigger the experiment_id fallback. Added IsNonEmptyString unit coverage, an opaque-LayerId pass-through integration test, an empty-LayerId fallback integration test, and a null-LayerId uniform-across-rule-types companion test. variation_id tests are unchanged.

Jira Ticket

FSSDK-12813

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