Skip to content

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

Merged
junaed-optimizely merged 8 commits into
masterfrom
ai/jaeopt/FSSDK-12813-holdout-event
Jun 30, 2026
Merged

[AI-FSSDK] [FSSDK-12813] Normalize decision event campaign_id, variation_id, and entity_id#415
junaed-optimizely merged 8 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

@junaed-optimizely junaed-optimizely merged commit 1d3c216 into master Jun 30, 2026
10 of 11 checks passed
@junaed-optimizely junaed-optimizely deleted the ai/jaeopt/FSSDK-12813-holdout-event branch June 30, 2026 15:23
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.

2 participants