Skip to content

fix(consult): changes for EPDN consult transfer#4948

Open
Shreyas281299 wants to merge 2 commits into
webex:task-refactorfrom
Shreyas281299:fix-epdn-consult
Open

fix(consult): changes for EPDN consult transfer#4948
Shreyas281299 wants to merge 2 commits into
webex:task-refactorfrom
Shreyas281299:fix-epdn-consult

Conversation

@Shreyas281299
Copy link
Copy Markdown
Contributor

@Shreyas281299 Shreyas281299 commented May 5, 2026

COMPLETES #N/A (EP-DN consult transfer defect fix)

This pull request addresses

EP-DN consult transfer regressions where task state and UI controls could drift after transfer-related event ordering differences. In affected flows, agents could see incorrect controls (consult/transfer/end visibility), incorrect consulted-role inference, or miss wrap-up progression after transfer.

by making the following changes

  • Added effective voice-state derivation to align UI/operation guards with latest interaction payload when XState snapshot lags.
  • Hardened transfer payload normalization in task lifecycle handling (wrapUpRequired and isConsulted inference), including owner-aware EP-DN consulted detection.
  • Updated state-machine guards/transitions for transfer and wrap-up handling (TRANSFER_SUCCESS routing and WRAPUP_COMPLETE completion handling).
  • Improved consult leg detection and consult-control computation for payloads with partial consult metadata.
  • Added/expanded unit coverage for TaskUtils, state machine transitions, effective voice state mapping, and UI control behavior.

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

  • Unit tests for uiControlsComputer consult-leg visibility and control enablement in EP-DN/partial-payload shapes.
  • Unit tests for TaskStateMachine transfer/wrap-up lifecycle behavior, including WRAPUP_COMPLETE progression.
  • Unit tests for effectiveVoiceTaskState wrap-up forcing and non-wrap-up fallbacks.
  • Unit tests for TaskUtils EP-DN consulted-recipient inference.
  • Manual validation of consult transfer/blind transfer edge cases (state + controls + wrap-up progression).

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 - Please Specify (ChatGPT Codex)
  • 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.

@Shreyas281299 Shreyas281299 requested a review from a team as a code owner May 5, 2026 09:22
@Shreyas281299
Copy link
Copy Markdown
Contributor Author

Changeset 8626ee4 — UI consult-leg visibility stabilization

What changed

  • Added getIsConsultInProgress() in TaskUtils to derive consult-in-progress from explicit task flag or consult media.
  • Updated uiControlsComputer to use this derived signal for consult leg visibility and control state.
  • Added unit tests in uiControlsComputer spec for payloads where consult media is unavailable and consult state must still be inferred.

Why it changed

  • EP-DN payload ordering can temporarily omit consult media/state details, causing UI controls to show incorrect leg/actions.
  • This changeset makes control rendering resilient to those transient payload shapes so users see the expected consult controls consistently.

@Shreyas281299
Copy link
Copy Markdown
Contributor Author

Changeset 6440016 — transfer/wrap-up/state-machine hardening for EP-DN consult flows

What changed

  • Added effectiveVoiceTaskState and wired it into UI computation and voice operation guards.
  • Improved TaskManager transfer payload normalization (wrapUpRequired and isConsulted inference), including EP-DN owner-aware consulted detection.
  • Updated state-machine guards/transitions to route transfer outcomes to WRAPPING_UP using per-agent wrap-up checks.
  • Added root handling for WRAPUP_COMPLETE so delayed event ordering still completes cleanup correctly.
  • Added/expanded tests for state machine, effective voice state, TaskUtils, and UI controls.

Why it changed

  • In consult/blind transfer edge cases, stale or partial backend payloads caused wrong control visibility, incorrect consulted-role inference, and missed wrap-up transitions.
  • This changeset aligns machine state + UI controls with the effective interaction state so both transfer recipient and transfer initiator follow the correct lifecycle and cleanup path.


const wasConsultedTask = Boolean(task?.data?.isConsulted);
const computeWrapUpRequired = () => {
const pending = message.data.agentsPendingWrapUp;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Inline note: this transfer-specific wrap-up derivation prioritizes agentsPendingWrapUp and participant isWrapUp for the current agent before fallback heuristics. That prevents Agent-2 from staying on active controls when backend transfer payloads don’t set wrapUpRequired consistently.


const participantWrapUp = taskData.interaction?.participants?.[selfId]?.isWrapUp === true;
if (participantWrapUp) return true;
const participants = taskData.interaction?.participants;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Inline note: shouldForceWrapUpForCurrentAgent() intentionally treats missing/self-left participant entries as wrap-up signals. In transfer races this makes UI state deterministic (WRAPPING_UP) even when machine state or payload flags arrive out of order.

},
// Wrapped-up can arrive while machine still reflects CONNECTED/CONSULTING due event ordering.
// Accept it globally so completion cleanup always runs and task is removed from collection.
[TaskEvent.WRAPUP_COMPLETE]: {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Inline note: this root-level WRAPUP_COMPLETE transition is added to handle event-ordering gaps where wrapped-up arrives before state reaches WRAPPING_UP; it guarantees completion/cleanup instead of leaving stale task cards.

// Stale relationshipType=consult often remains after consult transfer to a new primary owner.
// Only treat it as an active consult session for UI when the interaction is consulting or this
// task is the secondary (EP-DN) consult leg — not a warm-transferred main call.
const consultRelationshipAffectsConsultingUi = Boolean(
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Inline note: consultRelationshipAffectsConsultingUi narrows stale relationshipType=consult handling so only true consult contexts get consult controls. This avoids showing consult-only UI to a newly transferred primary owner.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

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: 64400163b2

ℹ️ 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 +607 to +610
const normalizedPayload: TaskData = {
...taskData,
isConsulted: this.resolveIsConsultedTaskFlag(taskData),
};
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 Preserve consulted flag when updates omit isConsulted

updateTaskData() now unconditionally rewrites isConsulted from resolveIsConsultedTaskFlag(taskData), which returns false whenever incoming payloads omit isConsulted (common for non-consult-specific updates like recording/contact refresh events). For an already-consulted task, this clears consulted status and enables full main-call controls incorrectly until another event restores it, changing transfer/end behavior for the consulted agent.

Useful? React with 👍 / 👎.

@@ -236,6 +250,26 @@ export const isSecondaryEpDnAgent = (interaction: Interaction): boolean => {
return interaction.mediaType === 'telephony' && isSecondaryAgent(interaction);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Inline note: owner-aware consulted detection is critical after consult transfer. Secondary EP-DN shape can still be present, but if interaction.owner is self, this task is now primary and must not remain in consulted-only UI/state handling.

service.send({type: TaskEvent.WRAPUP_COMPLETE});
expect(service.getSnapshot().value).toBe(TaskState.COMPLETED);
});

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Inline note: this test locks the transfer regression: if wrap-up completion arrives before explicit WRAPPING_UP, machine must still reach COMPLETED so cleanup/removal happens deterministically.

const state = this.getStateMachineSnapshot();
// Validate consult is allowed (use effective state when machine lags IDLE after transfer)
const effectiveState = this.getEffectiveVoiceTaskStateForOperation();
const canConsult =
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Inline note: consult validation here intentionally uses effective state (not raw snapshot) to handle post-transfer ordering where machine can temporarily lag at IDLE while payload already reflects an active voice leg.

data: wrapupPayload,
});

// Some transfer flows can miss or delay AGENT_WRAPPEDUP; complete locally on API success.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Inline note: local WRAPUP_COMPLETE dispatch on wrapup API success is a reliability guard. It prevents stale wrapup dropdown/task cards when websocket AGENT_WRAPPEDUP is delayed or dropped.

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