Skip to content

fix(contact-center): route transfers through consult transfer when consult leg remains active after conference downgrade - #5129

Open
bhabalan wants to merge 1 commit into
webex:nextfrom
bhabalan:CAI-8344-consult-fix
Open

fix(contact-center): route transfers through consult transfer when consult leg remains active after conference downgrade #5129
bhabalan wants to merge 1 commit into
webex:nextfrom
bhabalan:CAI-8344-consult-fix

Conversation

@bhabalan

Copy link
Copy Markdown
Contributor

COMPLETES #CAI-8344

This pull request addresses

When an agent is consulting another agent during a conference and a third agent exits, the backend downgrades the main call leg back to a 1:1 connected/hold state while the consult leg remains live. Voice.transfer() previously keyed off interaction.state === 'consulting', so it incorrectly issued a blind transfer against the main interaction instead of a consult transfer against the live consult leg.

This mismatch can leave the consult destination ringing or otherwise break the transfer flow after a conference downgrade.

by making the following changes

  • Add hasActiveConsultLeg() in Voice.ts to derive consulting state the same way UI controls do: state machine CONSULTING, else getTaskStateForUiControls(...) === CONSULTING.
  • Route transfer() through consultTransfer when that derived state is consulting, even if interaction.state reports connected/hold.
  • Target interaction.mainInteractionId (falling back to interactionId) for consult transfer requests after conference downgrade.
  • Export getTaskStateForUiControls from the state-machine barrel for reuse.
  • Add unit tests for conference-downgrade consult transfer (owner and non-owner), state-machine-only consulting detection, and the connected/no-consult blind-transfer regression.
  • Update task AI docs to clarify that consulting state is derived, not read from raw interaction.state.

Change Type

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Tooling change
  • Internal code refactor

The following scenarios were tested

Automated

  • yarn workspace @webex/contact-center test:unit --targets services/task/voice/Voice.ts — 32 tests passed
  • New coverage for TC-15/TC-16 conference-downgrade consult transfer paths, state-machine-only consulting detection, and connected/no-consult blind transfer regression

The GAI Coding Policy And Copyright Annotation Best Practices

  • GAI was not used (or, no additional notation is required)
  • Code was generated entirely by GAI
  • GAI was used to create a draft that was subsequently customized or modified
  • Coder created a draft manually that was non-substantively modified by GAI (e.g., refactoring was performed by GAI on manually written code)
  • Tool used for AI assistance (GitHub Copilot / Other - specify)
    • Github Copilot
    • Other - Cursor
  • This PR is related to
    • Feature
    • Defect fix
    • Tech Debt
    • Automation

I certified that

  • I have read and followed contributing guidelines
  • I discussed changes with code owners prior to submitting this pull request
  • I have not skipped any automated checks
  • All existing and new tests passed
  • I have updated the documentation accordingly

Make sure to have followed the contributing guidelines before submitting.

Made with Cursor

…nsult leg remains active after conference downgrade
@bhabalan
bhabalan requested a review from a team as a code owner July 28, 2026 22:46
@bhabalan bhabalan changed the title fix(contact-center): route transfers through consult transfer when consult leg remains active after conference downgrade (CAI-8344) fix(contact-center): route transfers through consult transfer when consult leg remains active after conference downgrade Jul 28, 2026
@bhabalan bhabalan added the validated If the pull request is validated for automation. label Jul 28, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 24110ba495

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +73 to +74
if (this.getStateMachineSnapshot()?.matches(TaskState.CONSULTING)) {
return true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Require consult ownership before selecting consult transfer

When an incoming or EP-DN consult is assigned with isConsulted: true while the raw interaction remains connected, guards.isConsultingAssignment moves the receiver's state machine to CONSULTING, even though uiControlsComputer.ts deliberately disables transfer when !consultInitiator. This new snapshot check therefore makes a direct call to the public transfer() method issue contact.consultTransfer from the consulted receiver, which cannot bridge the customer and consult legs. Include initiator/ownership in this decision rather than treating every CONSULTING snapshot as transferable.

Useful? React with 👍 / 👎.

Comment on lines +310 to +313
...dummyContact,
consultTransfer: jest.fn().mockResolvedValue('consultTransferred'),
blindTransfer: jest.fn().mockResolvedValue('blindTransferred'),
vteamTransfer: jest.fn().mockResolvedValue('vteamTransferred'),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Replace the new Jest mocks with Sinon stubs

The newly added transfer-contact helper creates its mocks with jest.fn(), contrary to the repository's explicit requirement that mocks and stubs use Sinon. Converting these new doubles to Sinon also prevents this change from further coupling the test helper to Jest-specific mock APIs.

AGENTS.md reference: AGENTS.md:L43-L47

Useful? React with 👍 / 👎.


// consult transfer path
if (this.data.interaction.state === 'consulting') {
if (isConsultTransfer) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Record the transfer-routing change in the contract catalog

This changes the routing semantics of the public Voice.transfer() API, but the commit updates only the task spec/source-material architecture document and leaves ai-docs/CONTRACTS.md and .sdd/manifest.json unchanged. The package workflow explicitly requires both artifacts to be updated when public behavior or routing changes, so add the corresponding contract and manifest updates to keep the authoritative catalog aligned with runtime behavior.

AGENTS.md reference: packages/@webex/contact-center/AGENTS.md:L66-L70

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

validated If the pull request is validated for automation.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant