Skip to content

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

Open
jaeopt wants to merge 1 commit into
masterfrom
ai/jaeopt/FSSDK-12813-holdout-event
Open

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

Conversation

@jaeopt

@jaeopt jaeopt commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Normalize the campaign_id, variation_id, and entity_id fields on outgoing decision events uniformly across every decision type (experiment, feature test, rollout, holdout) so the SDK emits cross-SDK byte-equivalent wire output. decisions[].campaign_id and impression events[].entity_id fall back to experiment_id when invalid; decisions[].variation_id becomes JSON null. The path never logs, errors, or blocks event dispatch.

Changes

  • Added pkg/event/event_id_normalizer.go with three pure helpers (IsNumericIDString, NormalizeCampaignID, NormalizeVariationID returning *string).
  • Wired the normalizer into the single impression path in pkg/event/factory.gocreateImpressionEvent normalizes from experiment.LayerID (falling back to experiment.ID for holdouts, which have no layer) and reuses the same value for EntityID. createImpressionVisitor re-applies normalization as defense-in-depth so the two fields cannot drift. Conversion path is untouched.
  • Changed Decision.VariationID to *string so non-numeric upstream values marshal to JSON null, matching the cross-SDK contract and the existing nullable-field convention used by DecisionMetadata.CmabUUID.
  • Audited existing event-builder tests per FR-011 — replaced non-numeric placeholders (holdout_123, holdout_var_123) with numeric IDs, updated holdout assertions to the normalized output with inline FSSDK-12813 references, and added unit and integration coverage for the new helpers and the full wire payload.

Notes

  • Decision.VariationID changing from string to *string is a Go-source-level breaking change for any downstream consumer that constructs event.Decision literals directly (no such usages exist in this repo outside the event package itself). The on-the-wire JSON contract is unchanged in shape and more permissive in values.

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