Skip to content

fix(personalize,import): fix CT linking failure from empty-audience experiences and missing variant entry data file - #280

Merged
cs-raj merged 7 commits into
developmentfrom
fix/DX-9469
Jul 10, 2026
Merged

fix(personalize,import): fix CT linking failure from empty-audience experiences and missing variant entry data file #280
cs-raj merged 7 commits into
developmentfrom
fix/DX-9469

Conversation

@cs-raj

Copy link
Copy Markdown
Contributor

Two related bugs in the Personalize import pipeline:

  1. experiences.ts — 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 changing importExperienceVersions to return boolean and only adding UIDs to the pending set when valid variants were actually submitted. Also adds a null guard in attachCTsInExperience before accessing variantGroup to prevent a silent crash.

  2. entries.ts — a bare return inside the no-environments-file branch of the entries import function exited the entire function, skipping createEntryDataForVariantEntry(). This meant data-for-variant-entry.json was never written whenever a stack had no environments, causing the variant-entries module to warn about the missing file and skip all variant entry imports. Fixed by removing the return.

Problems

Bug 1 — CT linking broken when any experience has empty audiences

When importing a stack that contains experiences with referredAudiences: [] (AB
tests or segmented experiences with no audiences, or with only Lytics audiences),
the CLI fails to link any variant group to any content type — even for other
experiences in the same import that do have valid audiences.

Steps to reproduce:

  1. Export a stack with at least one experience that has empty referredAudiences
  2. Import into a new stack
  3. All content-type ↔ variant-group links are missing across the entire import

Bug 2 — Variant entry data file never written when no environments exist

When the imported stack has no environments, the entries import function hits an
early return before createEntryDataForVariantEntry() runs. The file
mapper/entries/data-for-variant-entry.json is never created, so the
variant-entries module warns "Variant entry data file not found" and skips all
variant entry imports silently.


Root Causes

Bug 1:pendingVariantAndVariantGrpForExperience was built from the full
experiencesUidMapper — all created experience UIDs regardless of whether valid
variants were submitted. Experiences with variants: [] never trigger variant-group
creation in the Personalize backend. The validation polling loop exhausted all 6
retries (60 s) waiting for groups that would never appear, then set
personalizeConfig.importData = false, gating attachCTsInExperience for the
entire import.

Bug 2: Inside if (!skipEntriesPublish), when this.envs was empty, a bare
return exited the whole import function. createEntryDataForVariantEntry() at
the end of the function was never reached.


Fixes

contentstack-variants/src/import/experiences.ts

  1. importExperienceVersions return typePromise<void>Promise<boolean>

    • false: no versions file, variants: [], or all variants stripped by lookUpAudiences
    • true: at least one valid version was submitted to the Personalize API
  2. Caller uses the return valueSet<string> experienceUidsWithVariants
    collects UIDs only when importExperienceVersions returns true.
    pendingVariantAndVariantGrpForExperience = Array.from(experienceUidsWithVariants)

  3. Null guard in attachCTsInExperiencegetVariantGroup can return empty
    variant_groups: [], making variantGroup undefined. Added guard before
    accessing it to log a warn and skip instead of crashing silently inside
    Promise.allSettled.

contentstack-import/src/import/modules/entries.ts

Removed the bare return from the no-environments-found branch. The publish loop
degrades gracefully with empty envs (serializePublishEntries nulls out all entries
when no environment matches), and createEntryDataForVariantEntry() now always runs.


Edge Cases Confirmed Safe

  • All experiences have empty audiences → pending list empty → validation resolves
    immediately → attachCTsInExperience called → null guard handles missing variant groups
  • Mixed (some empty, some valid) → only valid UIDs polled → validation succeeds → CT linking works
  • No environments file → publish loop runs but makes zero API calls → variant entry data file written correctly

Files Changed

FileChange
contentstack-variants/src/import/experiences.tsBug 1 core fix + null guard
contentstack-import/src/import/modules/entries.tsBug 2 fix — remove early return
contentstack-variants/test/unit/import/experiences.test.tsNew — 15 unit tests
contentstack-variants/test/unit/mock/contents/personalize/experiences/experiences.jsonNew mock
contentstack-variants/test/unit/mock/contents/personalize/experiences/versions/*.jsonNew mocks
contentstack-variants/test/unit/mock/contents/mapper/personalize/audiences/uid-mapping.jsonNew mock

cs-rajand others added 2 commits July 10, 2026 08:44
…xperiences and missing variant entry data file [DX-9469]
Two related bugs in the Personalize import pipeline:
1. experiences.ts — 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 changing
importExperienceVersions to return boolean and only adding UIDs to the pending set
when valid variants were actually submitted. Also adds a null guard in
attachCTsInExperience before accessing variantGroup to prevent a silent crash.
2. entries.ts — a bare return inside the no-environments-file branch of the entries
import function exited the entire function, skipping createEntryDataForVariantEntry().
This meant data-for-variant-entry.json was never written whenever a stack had no
environments, causing the variant-entries module to warn about the missing file and
skip all variant entry imports. Fixed by removing the return.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…DX-9469
Revert changes to audiences.test.ts, variant-entries.test.ts, and
package.json (test script narrowing) — these were workarounds for the
ESM/uuid runner issue and are not part of the DX-9469 fix scope.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@cs-raj
cs-raj requested a review from a team as a code ownerJuly 10, 2026 03:22
@github-actions

Copy link
Copy Markdown

🔒 Security Scan Results

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

Check TypeCount (with fixes)Without fixesThresholdResult
🔴 Critical Severity0010✅ Passed
🟠 High Severity0025✅ Passed
🟡 Medium Severity01500✅ Passed
🔵 Low Severity001000✅ Passed

⏱️ SLA Breach Summary

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

SeverityBreaches (with fixes)Breaches (no fixes)SLA Threshold (with/no fixes)Status
🔴 Critical0015 / 30 days✅ Passed
🟠 High0030 / 120 days✅ Passed
🟡 Medium0190 / 365 days⚠️ Warning
🔵 Low00180 / 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.

@github-actions

Copy link
Copy Markdown

🔒 Security Scan Results

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

Check TypeCount (with fixes)Without fixesThresholdResult
🔴 Critical Severity0010✅ Passed
🟠 High Severity0025✅ Passed
🟡 Medium Severity01500✅ Passed
🔵 Low Severity001000✅ Passed

⏱️ SLA Breach Summary

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

SeverityBreaches (with fixes)Breaches (no fixes)SLA Threshold (with/no fixes)Status
🔴 Critical0015 / 30 days✅ Passed
🟠 High0030 / 120 days✅ Passed
🟡 Medium0190 / 365 days⚠️ Warning
🔵 Low00180 / 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.

cs-rajand others added 2 commits July 10, 2026 08:59
…h empty envs [DX-9469]
After removing the bare return, publishEntries is called even when no
environments exist — serializePublishEntries handles empty envs as a
no-op. Updated test assertion to reflect this and added assertion that
createEntryDataForVariantEntry always runs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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 TypeCount (with fixes)Without fixesThresholdResult
🔴 Critical Severity0010✅ Passed
🟠 High Severity0025✅ Passed
🟡 Medium Severity01500✅ Passed
🔵 Low Severity001000✅ Passed

⏱️ SLA Breach Summary

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

SeverityBreaches (with fixes)Breaches (no fixes)SLA Threshold (with/no fixes)Status
🔴 Critical0015 / 30 days✅ Passed
🟠 High0030 / 120 days✅ Passed
🟡 Medium0190 / 365 days⚠️ Warning
🔵 Low00180 / 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.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Fixes two import-pipeline bugs that could (a) prevent Content Type ↔ Variant Group linking across an entire Personalize import when some experiences have no valid variants, and (b) skip generating the variant-entry data file when the stack has no environments—causing variant entry imports to be skipped.

Changes:

  • Personalize experiences import: only poll/validate variant-group creation for experiences where at least one valid version/variant was actually submitted; add a guard when variant groups are missing during CT attachment.
  • Entries import: remove the early return on missing environments so createEntryDataForVariantEntry() always runs.
  • Add focused unit tests and mock fixtures covering empty-audience / lytics-only / mixed / missing-versions-file scenarios.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
packages/contentstack-variants/src/import/experiences.tsTracks only experiences with valid variants for validation polling; adds null-guard before CT attachment to missing variant groups.
packages/contentstack-variants/src/import/variant-entries.tsDowngrades missing data-for-variant-entry.json message from warn to debug and clarifies “no variant entries to import”.
packages/contentstack-import/src/import/modules/entries.tsRemoves early return on missing environments so variant entry data file creation always occurs.
packages/contentstack-import/test/unit/import/modules/entries.test.tsUpdates expectations to ensure publish path is exercised and variant-entry data file creation always runs.
packages/contentstack-variants/test/unit/import/experiences.test.tsAdds unit/integration tests for importExperienceVersions and pending validation list behavior.
packages/contentstack-variants/test/unit/mock/contents/personalize/experiences/experiences.jsonAdds experience fixtures used by tests.
packages/contentstack-variants/test/unit/mock/contents/personalize/experiences/experiences-content-types.jsonAdds content-type mapping fixtures for CT attachment tests.
packages/contentstack-variants/test/unit/mock/contents/personalize/experiences/versions/*.jsonAdds version fixtures for valid/mixed/lytics-only/empty/draft scenarios.

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

Comment threadpackages/contentstack-variants/src/import/experiences.ts Outdated
Comment threadpackages/contentstack-import/src/import/modules/entries.ts
- experiences.ts: pass versionReqObj (already audience-mapped) to
lookUpEvents instead of original version — was relying on mutation
side effect of lookUpAudiences to make this work
- entries.ts: skip publish loop and success log entirely when envs is
empty, instead of running the loop as a no-op; createEntryDataForVariantEntry
still runs unconditionally afterward
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 TypeCount (with fixes)Without fixesThresholdResult
🔴 Critical Severity0010✅ Passed
🟠 High Severity0025✅ Passed
🟡 Medium Severity01500✅ Passed
🔵 Low Severity001000✅ Passed

⏱️ SLA Breach Summary

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

SeverityBreaches (with fixes)Breaches (no fixes)SLA Threshold (with/no fixes)Status
🔴 Critical0015 / 30 days✅ Passed
🟠 High0030 / 120 days✅ Passed
🟡 Medium0190 / 365 days⚠️ Warning
🔵 Low00180 / 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.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 13 out of 13 changed files in this pull request and generated 1 comment.

Comment threadpackages/contentstack-variants/src/import/experiences.ts
…X-9469]
If versionReqObj.status was e.g. PAUSED (not PAUSE), the previous code
silently added a 4th key to the Record-typed map, causing Object.values
to find a non-undefined entry and return true — even though
handleVersionUpdateOrCreate only destructures ACTIVE/DRAFT/PAUSE and
would have processed nothing. The experience UID then incorrectly entered
the polling pending list, reintroducing the timeout bug.
Fix: narrow versionMap to a typed object with only the three known keys
and validate status against a HANDLED_STATUSES set before writing.
Unrecognized statuses are logged and skipped.
Also aligns the variant-skip warning message with the generic wording
adopted in fix/DX-9469-v2.
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 TypeCount (with fixes)Without fixesThresholdResult
🔴 Critical Severity0010✅ Passed
🟠 High Severity0025✅ Passed
🟡 Medium Severity01500✅ Passed
🔵 Low Severity001000✅ Passed

⏱️ SLA Breach Summary

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

SeverityBreaches (with fixes)Breaches (no fixes)SLA Threshold (with/no fixes)Status
🔴 Critical0015 / 30 days✅ Passed
🟠 High0030 / 120 days✅ Passed
🟡 Medium0190 / 365 days⚠️ Warning
🔵 Low00180 / 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.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 13 out of 13 changed files in this pull request and generated 1 comment.

Comment threadpackages/contentstack-variants/src/import/experiences.ts

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 13 out of 13 changed files in this pull request and generated 2 comments.

Comment threadpackages/contentstack-variants/src/import/variant-entries.ts
Comment threadpackages/contentstack-import/src/import/modules/entries.ts
@cs-raj
cs-raj merged commit faf0c2c into developmentJul 10, 2026
12 checks passed
@cs-raj
cs-raj deleted the fix/DX-9469 branch July 10, 2026 09:45
Sign up for freeto 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

@cs-raj@netrajpatel@naman-contentstack