Skip to content

fix(personalize): fix CT linking failure from empty-audience experiences #281

Merged
cs-raj merged 4 commits into
v2-devfrom
fix/DX-9469-v2
Jul 10, 2026
Merged

fix(personalize): fix CT linking failure from empty-audience experiences #281
cs-raj merged 4 commits into
v2-devfrom
fix/DX-9469-v2

Conversation

@cs-raj

@cs-raj cs-raj commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes a bug in the Personalize import pipeline where experiences whose audience mappings are all empty (e.g. Lytics-only or unmapped CS audiences) were incorrectly added to the variant polling queue, causing the validation to time out and importData to be set to false — which in turn skipped content-type linking for all experiences in the import.

Root Cause

importExperienceVersions did not return a boolean indicating whether variants were actually submitted to the Personalize backend. As a result, every experience's UID was unconditionally added to pendingVariantAndVariantGrpForExperience, even those where all audience references were unmapped (so no API call was made). The polling loop then waited the full threshold timer (60 s) waiting for variant groups that would never be created, then set importData = false, blocking CT attachment for all experiences.

Additionally, attachCTsInExperience had no null guard on the variantGroup returned by getVariantGroup, which could throw if the backend returned an empty list.

Changes

packages/contentstack-variants/src/import/experiences.ts

  • importExperienceVersions now returns Promise<boolean>:

    • Returns false when the versions file doesn't exist
    • Returns false when the versionMap is all-undefined (every version had its variants stripped by audience lookup)
    • Returns true only after handleVersionUpdateOrCreate is called (i.e. something was actually submitted)
  • import() — replaced values(cloneDeep(experiencesUidMapper)) with a Set<string> that only collects UIDs where importExperienceVersions returned true. Pending list is built with Array.from(experienceUidsWithVariants) after the loop.

  • attachCTsInExperience — added null guard: if getVariantGroup returns no variantGroup, log a warning and skip instead of throwing.

packages/contentstack-variants/test/unit/import/experiences.test.ts

Added 11 new test cases covering the fix:

Group Cases
importExperienceVersions no versions file → false; Lytics-only audiences → false; unmapped CS audiences → false; valid ACTIVE → true; valid DRAFT-only → true
Pending list (Set-based) empty experiences → pending stays []; no-valid-versions experience not added; valid-versions experience added
validateVariantGroupAndVariantsCreated empty pending list resolves true immediately (no API calls)
attachCTsInExperience null guard missing variantGroup skips gracefully; present variantGroup attaches correctly

packages/contentstack-variants/test/helpers/mocha-root-hooks.js

Guarded loadChalk as optional — not exported in the current installed version of @contentstack/cli-utilities, which caused the entire test suite to fail before any test ran.

Test Results

60 passing (278ms)

Impact

Scenario Before After
All experiences have valid CS audiences CT linking works CT linking works (no regression)
Some experiences have Lytics/unmapped audiences Validation times out → all CT linking skipped Affected experiences skipped cleanly; others link correctly
All experiences have empty audiences Validation times out → importData=false → no CT linking Pending list is empty → validation resolves immediately → CT linking skipped cleanly
getVariantGroup returns empty list Uncaught TypeError on variantGroup.content_types Warning logged, experience skipped gracefully

cs-raj and others added 2 commits July 10, 2026 09:39
…ces [DX-9469]

pendingVariantAndVariantGrpForExperience was populated with ALL created
experience UIDs regardless of whether valid variants were submitted to the
API. Experiences with variants:[] never get variant groups from the
Personalize backend, so the validation loop timed out and set
importData=false, skipping attachCTsInExperience for every experience
including valid ones.

Fixed by:
1. Adding a versionMap guard in importExperienceVersions (returns boolean)
   so only experiences that actually submitted variants return true
2. Only adding UIDs to the pending set when importExperienceVersions
   returns true
3. Adding a null guard in attachCTsInExperience before accessing
   variantGroup to prevent a silent crash inside Promise.allSettled

Note: Bug 2 (missing data-for-variant-entry.json) is not present in v2
— processCleanup always calls createEntryDataForVariantEntry regardless
of environments.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add 11 test cases covering importExperienceVersions returning false
  for missing file, Lytics-only audiences, and unmapped CS audiences
- Add tests verifying Set-based pending list only includes experiences
  with valid variants submitted to Personalize
- Add tests for validateVariantGroupAndVariantsCreated resolving
  immediately when pending list is empty
- Add tests for attachCTsInExperience null guard skipping gracefully
  when variantGroup is missing
- Fix mocha-root-hooks.js to guard loadChalk as optional (not exported
  in current cli-utilities version)
- Fix importExperienceVersions to return false (not undefined) when
  versions file does not exist, for consistent boolean API

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@cs-raj cs-raj requested a review from a team as a code owner July 10, 2026 04:34
@github-actions

Copy link
Copy Markdown

🔒 Security Scan Results

ℹ️ Note: Only vulnerabilities with available fixes (upgrades or patches) are counted toward thresholds.

Check Type Count (with fixes) Without fixes Threshold Result
🔴 Critical Severity 0 0 10 ✅ Passed
🟠 High Severity 0 0 25 ✅ Passed
🟡 Medium Severity 1 1 500 ✅ Passed
🔵 Low Severity 0 0 1000 ✅ Passed

⏱️ SLA Breach Summary

⚠️ Warning: The following vulnerabilities have exceeded their SLA thresholds (days since publication).

Severity Breaches (with fixes) Breaches (no fixes) SLA Threshold (with/no fixes) Status
🔴 Critical 0 0 15 / 30 days ✅ Passed
🟠 High 0 0 30 / 120 days ✅ Passed
🟡 Medium 0 1 90 / 365 days ⚠️ Warning
🔵 Low 0 0 180 / 365 days ✅ Passed

ℹ️ Vulnerabilities Without Available Fixes (Informational Only)

The following vulnerabilities were detected but do not have fixes available (no upgrade or patch). These are excluded from failure thresholds:

  • Critical without fixes: 0
  • High without fixes: 0
  • Medium without fixes: 1
  • Low without fixes: 0

⚠️ BUILD PASSED WITH WARNINGS - SLA breaches detected for issues without available fixes

Consider reviewing these vulnerabilities when fixes become available.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a Personalize experiences import edge case where experiences with no mappable audiences were still added to the variant polling queue, causing validation timeouts that flipped importData=false and skipped content-type (CT) attachment for the whole import.

Changes:

  • Make importExperienceVersions return a boolean indicating whether variants were actually submitted, and only queue those experiences for variant/variant-group validation.
  • Add a null guard in attachCTsInExperience when getVariantGroup returns no groups, logging a warning and skipping instead of throwing.
  • Add unit tests covering “no versions / no valid variants / Set-based pending list / empty pending validation / CT attach null-guard”, and harden mocha root hooks to treat loadChalk as optional.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
packages/contentstack-variants/src/import/experiences.ts Only validates/polls for experiences that actually submitted variants; avoids CT-attach crash when variant group is missing.
packages/contentstack-variants/test/unit/import/experiences.test.ts Adds unit coverage for boolean-return behavior, Set-based pending queue, empty-pending validation fast-path, and CT attach null-guard.
packages/contentstack-variants/test/helpers/mocha-root-hooks.js Avoids failing the entire test suite when loadChalk is not exported by the installed @contentstack/cli-utilities.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/contentstack-variants/src/import/experiences.ts
Message was blaming Lytics audiences specifically but the branch fires
for any mapping failure (CS or Lytics). Broadened to "after
audience/event mapping".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

🔒 Security Scan Results

ℹ️ Note: Only vulnerabilities with available fixes (upgrades or patches) are counted toward thresholds.

Check Type Count (with fixes) Without fixes Threshold Result
🔴 Critical Severity 0 0 10 ✅ Passed
🟠 High Severity 0 0 25 ✅ Passed
🟡 Medium Severity 1 1 500 ✅ Passed
🔵 Low Severity 0 0 1000 ✅ Passed

⏱️ SLA Breach Summary

⚠️ Warning: The following vulnerabilities have exceeded their SLA thresholds (days since publication).

Severity Breaches (with fixes) Breaches (no fixes) SLA Threshold (with/no fixes) Status
🔴 Critical 0 0 15 / 30 days ✅ Passed
🟠 High 0 0 30 / 120 days ✅ Passed
🟡 Medium 0 1 90 / 365 days ⚠️ Warning
🔵 Low 0 0 180 / 365 days ✅ Passed

ℹ️ Vulnerabilities Without Available Fixes (Informational Only)

The following vulnerabilities were detected but do not have fixes available (no upgrade or patch). These are excluded from failure thresholds:

  • Critical without fixes: 0
  • High without fixes: 0
  • Medium without fixes: 1
  • Low without fixes: 0

⚠️ BUILD PASSED WITH WARNINGS - SLA breaches detected for issues without available fixes

Consider reviewing these vulnerabilities when fixes become available.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment thread packages/contentstack-variants/src/import/experiences.ts
…orts [DX-9469]

Both were made redundant by the Set-based pending list introduced in the
DX-9469 fix. Leaving them risks build failures under noUnusedLocals or
ESLint unused-import rules.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

🔒 Security Scan Results

ℹ️ Note: Only vulnerabilities with available fixes (upgrades or patches) are counted toward thresholds.

Check Type Count (with fixes) Without fixes Threshold Result
🔴 Critical Severity 0 0 10 ✅ Passed
🟠 High Severity 0 0 25 ✅ Passed
🟡 Medium Severity 1 1 500 ✅ Passed
🔵 Low Severity 0 0 1000 ✅ Passed

⏱️ SLA Breach Summary

⚠️ Warning: The following vulnerabilities have exceeded their SLA thresholds (days since publication).

Severity Breaches (with fixes) Breaches (no fixes) SLA Threshold (with/no fixes) Status
🔴 Critical 0 0 15 / 30 days ✅ Passed
🟠 High 0 0 30 / 120 days ✅ Passed
🟡 Medium 0 1 90 / 365 days ⚠️ Warning
🔵 Low 0 0 180 / 365 days ✅ Passed

ℹ️ Vulnerabilities Without Available Fixes (Informational Only)

The following vulnerabilities were detected but do not have fixes available (no upgrade or patch). These are excluded from failure thresholds:

  • Critical without fixes: 0
  • High without fixes: 0
  • Medium without fixes: 1
  • Low without fixes: 0

⚠️ BUILD PASSED WITH WARNINGS - SLA breaches detected for issues without available fixes

Consider reviewing these vulnerabilities when fixes become available.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

@cs-raj cs-raj merged commit e39a8a8 into v2-dev Jul 10, 2026
11 checks passed
@cs-raj cs-raj deleted the fix/DX-9469-v2 branch July 10, 2026 09:44
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.

4 participants