Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions ai-docs/CONTRACTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ The aggregator package `@webex/cc-widgets` re-exports every widget plus the `sto
| cc-widgets.UserState | `@webex/cc-user-state` | `UserState` | React component; custom element `widget-cc-user-state`; prop `onStateChange` (function) | stable semver | `packages/contact-center/user-state/ai-docs/user-state-spec.md` | `packages/contact-center/user-state/src/index.ts` |
| cc-widgets.IncomingTask | `@webex/cc-task` | `IncomingTask` | React component; custom element `widget-cc-incoming-task`; props `incomingTask` (json), `onAccepted`, `onRejected` (functions) | stable semver | `packages/contact-center/task/ai-docs/task-spec.md` | `packages/contact-center/task/src/index.ts` |
| cc-widgets.CallControl | `@webex/cc-task` | `CallControl` | React component; custom element `widget-cc-call-control`; props `onHoldResume`, `onEnd`, `onWrapUp`, `onRecordingToggle` (functions) | stable semver | `packages/contact-center/task/ai-docs/task-spec.md` | `packages/contact-center/task/src/index.ts` |
| cc-widgets.CallControlCAD | `@webex/cc-task` | `CallControlCAD` | React component; custom element `widget-cc-call-control-cad`; props `onHoldResume`, `onEnd`, `onWrapUp`, `onRecordingToggle` (functions) | stable semver | `packages/contact-center/task/ai-docs/task-spec.md` | `packages/contact-center/task/src/index.ts` |
| cc-widgets.CallControlCAD | `@webex/cc-task` | `CallControlCAD` | React component; custom element `widget-cc-call-control-cad`; props `onHoldResume`, `onEnd`, `onWrapUp`, `onRecordingToggle` (functions); owner-aware participant Drop is store-driven and adds no prop/attribute | stable semver | `packages/contact-center/task/ai-docs/task-spec.md`; `ai-docs/features/participant-drop-intake.md` | `packages/contact-center/task/src/index.ts` |
| cc-widgets.TaskList | `@webex/cc-task` | `TaskList` | React component; custom element `widget-cc-task-list`; props `onTaskAccepted`, `onTaskDeclined`, `onTaskSelected` (functions), `hasCampaignPreviewEnabled` (boolean) | stable semver | `packages/contact-center/task/ai-docs/task-spec.md` | `packages/contact-center/task/src/index.ts` |
| cc-widgets.OutdialCall | `@webex/cc-task` | `OutdialCall` | React component; custom element `widget-cc-outdial-call`; no declared props | stable semver | `packages/contact-center/task/ai-docs/task-spec.md` | `packages/contact-center/task/src/index.ts` |
| cc-widgets.RealTimeTranscript | `@webex/cc-task` | `RealTimeTranscript` | React component; custom element `widget-cc-realtime-transcript`; props `liveTranscriptEntries` (json), `className` (string) | stable semver | `packages/contact-center/task/ai-docs/task-spec.md` | `packages/contact-center/task/src/index.ts` |
Expand All @@ -26,14 +26,15 @@ The aggregator package `@webex/cc-widgets` re-exports every widget plus the `sto
| store.types | `@webex/cc-store` | Existing queue/entry-point request, response, and entity type re-exports plus `TaskUIControls` | TypeScript exports describing the SDK-backed domain surface; established entity rows and Task destination controls pass through without a widget destination abstraction | stable semver; SDK-shaped types track SDK | `@webex/contact-center` types (`node_modules/@webex/contact-center/dist/types/index.d.ts`) (SDK source); `packages/contact-center/store/ai-docs/store-spec.md` | `packages/contact-center/store/src/store.types.ts` |
| cc-components.consult-transfer-lists | `@webex/cc-components` | `CallControl` consult/transfer fetch props plus `action`, `availableDestinations`, and optional list-item `presence` | `FetchPaginatedList<ContactServiceQueue>` / `FetchPaginatedList<EntryPointRecord>` and the SDK-ordered destination array from `TaskUIControls`; UI preserves list/category order, passes buddy availability to Momentum Avatar as semantic presence, shows `AddressBookEntry.number` and `EntryPointRecord.number` subtitles, and may only apply host hide overrides | stable semver; entity and control types track store/SDK contracts; optional presentation prop is additive | `packages/contact-center/cc-components/ai-docs/cc-components-spec.md`; `ai-docs/features/consult-transfer-list-policy/spec/feature-spec.md` | `packages/contact-center/cc-components/src/components/task/task.types.ts` |
| store.constants | `@webex/cc-store` | Value/enum re-exports (`CC_EVENTS`, `TASK_EVENTS`, `LoginOptions`, `ConsultStatus`, `CAMPAIGN_PREVIEW_OUTBOUND_TYPES`, `DESKTOP`, `EXTENSION`, etc.) | Exported consts/enums for event names and login/consult/campaign domain values | stable semver | `packages/contact-center/store/ai-docs/store-spec.md` | `packages/contact-center/store/src/store.types.ts:368-403` |
| store.task-utils | `@webex/cc-store` | Pure task helpers (`isIncomingTask`, `getTaskStatus`, `getConsultStatus`, `getConferenceParticipants`, `isInteractionOnHold`, `findHoldStatus`, etc.) | `(task: ITask, agentId?: string) => boolean \| string \| number \| Participant[]` selectors over SDK task objects | stable semver | `packages/contact-center/store/ai-docs/store-spec.md` | `packages/contact-center/store/src/task-utils.ts` |
| store.task-utils | `@webex/cc-store` | Pure task helpers (`isIncomingTask`, `getTaskStatus`, `getConsultStatus`, `getConferenceParticipants`, `getConferenceParticipantDropRoster`, `isInteractionOnHold`, `findHoldStatus`, etc.) | Read-only selectors over SDK task objects; the Drop selector returns an owner-aware main-leg roster plus the current Entry Point/EP-DN consult destination (dialed number while ringing, answering Agent name before merge), or `null` for Customer-only/terminal calls | stable semver | `packages/contact-center/store/ai-docs/store-spec.md`; `ai-docs/features/participant-drop-intake.md` | `packages/contact-center/store/src/task-utils.ts` |
| ui-logging.withMetrics | `@webex/cc-ui-logging` | `withMetrics` | `withMetrics<P extends object>(Component, widgetName: string): React.MemoExoticComponent` HOC that auto-emits mount/unmount/error metrics; every widget export is wrapped with it | stable semver; signature change is breaking | `packages/contact-center/ui-logging/ai-docs/ui-logging-spec.md` | `packages/contact-center/ui-logging/src/index.ts` |
| ui-logging.WidgetMetrics | `@webex/cc-ui-logging` | `WidgetMetrics` (type) | `{ widgetName; event: 'WIDGET_MOUNTED' \| 'ERROR' \| 'WIDGET_UNMOUNTED' \| 'PROPS_UPDATED'; props?; timestamp; additionalContext? }` | stable semver; narrowing the `event` union or removing a field is breaking | `packages/contact-center/ui-logging/ai-docs/ui-logging-spec.md` | `packages/contact-center/ui-logging/src/index.ts` |

## Requires — what this repo depends on
| Dependency (service / package / datastore) | What is consumed | Schema / detail link | Availability assumption | Fallback on failure | Version floor |
|---|---|---|---|---|---|
| `@webex/contact-center` SDK | The CC runtime, including existing `getBuddyAgents`/`getQueues`/`getEntryPoints` methods, established queue records and entry-point response wrapper with mapped `number`, ordered Task destination controls, CC/task events, agent `Profile`, and host credentials | `@webex/contact-center` types (`node_modules/@webex/contact-center/dist/types/index.d.ts`); operations are consumed via the store and Task controls arrive on SDK task objects | Host establishes the authenticated Webex session; SDK assumed reachable | Store methods log and rethrow SDK failures; widget hooks apply their existing empty/error UI fallbacks | `3.12.0-next.106`, pinned by the store package dependency |
| `@webex/contact-center` SDK | The entire CC runtime: `Webex.init()`, `webex.cc.*` methods, `ITask.dropConferenceParticipant({participantId})`, CC/task event stream, agent `Profile`, `webex.credentials.getUserToken()` | `@webex/contact-center` types (`node_modules/@webex/contact-center/dist/types/index.d.ts`); consumed only via the store/task object | Host establishes the authenticated Webex session; SDK and routing backend are assumed reachable and authoritative | `Store.init()` rejects after a 6s init timeout; participant Drop rejects and `CallControlCAD` shows generic feedback | Pinned by the SDK dependency in each package's `package.json`; Participant Drop requires the published SDK version recorded in the feature intake |

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.

[P2] Merge the duplicate SDK contract row

This adds a second @webex/contact-center dependency row immediately above the existing one, leaving two canonical descriptions and two different version-floor statements. Merge the participant-drop API and fallback details into the existing row and retain its exact 3.12.0-next.106 version floor.

| `@webex/contact-center` SDK | The CC runtime, including existing `getBuddyAgents`/`getQueues`/`getEntryPoints` methods, established queue records and entry-point response wrapper with mapped `number`, ordered Task destination controls, CC/task events, agent `Profile`, and host credentials | `@webex/contact-center` types (`node_modules/@webex/contact-center/dist/types/index.d.ts`); operations are consumed via the store and Task controls arrive on SDK task objects | Host establishes the authenticated Webex session; SDK assumed reachable | Store methods log and rethrow SDK failures; widget hooks apply their existing empty/error UI fallbacks | `3.12.0-next.109`, pinned by the store package dependency |
| `react` / `react-dom` (18) | Component runtime; consumer peer dependency | React docs | Provided by host or bundled | N/A (build-time/runtime peer) | React 18 |
| `mobx` / `mobx-react-lite` | Store reactivity (`runInAction`, `observer`) | MobX docs | Bundled with store package | N/A | per `package.json` |
| `@r2wc/react-to-web-component` | Wraps React widgets as custom elements (`packages/contact-center/cc-widgets/src/wc.ts:1`) | r2wc docs | Bundled with `cc-widgets` | N/A | per `package.json` |
Expand Down
3 changes: 2 additions & 1 deletion ai-docs/SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ This repo is a client-side React/Web-Component widget library. It hosts no netwo

## Authentication & Authorization Model
- **Authentication:** Owned by the host app and the Webex SDK, not this repo. The host supplies either a live `webex` instance or `{webexConfig, access_token}`; the store passes the token to `Webex.init({credentials: {access_token}})` and otherwise treats identity as opaque (`packages/contact-center/store/src/store.ts:144-151`). Token retrieval for downstream SDK features delegates to the SDK: `getAccessToken()` calls `webex.credentials.getUserToken()` (`packages/contact-center/store/src/storeEventsWrapper.ts:988-998`).
- **Authorization:** Owned by the SDK / back end. The store surfaces the agent's capabilities as read-only feature flags derived from the SDK-provided `Profile` (`packages/contact-center/store/src/util.ts:3-36`); widgets use these only to show/hide UI. There is no access-decision logic enforced in this repo.
- **Authorization:** Owned by the SDK / back end. The store surfaces the agent's capabilities as read-only feature flags derived from the SDK-provided `Profile` (`packages/contact-center/store/src/util.ts:3-36`); widgets use these only to show/hide UI. Participant Drop additionally hides actions unless `interaction.owner === currentAgentId`, but that client rule is not an authorization boundary; the backend must authorize every request.
- **Default posture:** Widgets are inert until the host completes `Store.init()`; with no valid host-supplied session the SDK never initializes (`Webex.init` rejects after a 6s timeout — `packages/contact-center/store/src/store.ts:140-142`), so no agent data flows.

## Secret & Credential Handling
Expand All @@ -42,6 +42,7 @@ This repo is a client-side React/Web-Component widget library. It hosts no netwo
|---|---|---|---|
| `ui-logging` metrics props | Widget props are logged without sanitization — acknowledged in the `havePropsChanged` JSDoc `@remarks` (`metricsLogger.ts:73-76`) | Callers must not pass PII-bearing objects as metrics props; sanitization is noted as a future enhancement | cc-ui-logging maintainers |
| `getAccessToken()` SDK gap | `webex.credentials.getUserToken()` is `@ts-expect-error`-typed (SDK API not yet typed) (`storeEventsWrapper.ts:990-992`) | Token value is returned to the caller and never logged; failures log only an error message | cc-store maintainers |
| Participant Drop identity | Target IDs can be agent identifiers or customer ANI/DNIS and therefore may be sensitive | Derive in memory, pass only to `task.dropConferenceParticipant`, render through React text escaping, and log only static context plus generic feedback | cc-store / cc-task maintainers |

## Reporting & Review
- Security-relevant changes (anything touching the store init/credential path, the `@webex/contact-center` SDK boundary, logging, or the public export/custom-element surface) require review by the package CODEOWNERS on the `next`-targeted PR, following `.github/PULL_REQUEST_TEMPLATE.md` (FedRAMP/GAI sections). Suspected vulnerabilities: report through the Webex internal security channel, not a public issue.
Expand Down
1 change: 1 addition & 0 deletions ai-docs/SPEC_INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,6 @@ The intake record confirms scope/modules **against the code** and sets the chang
| Decision records | `ai-docs/adr/` | Standing ADRs — why the architecture is the way it is |
| Review catalog | `ai-docs/REVIEW_CHECKLIST.md` | 6-core + 4-coverage + 3-cross-cutting review checks |
| SDK reference | `@webex/contact-center` types (`node_modules/@webex/contact-center/dist/types/index.d.ts`) | installed SDK `.d.ts` surface — verify every SDK call |
| Participant Drop intake | `ai-docs/features/participant-drop-intake.md` | Cross-repository SDK/widget contract, behavior, delivery gates, and verification |

_No `DATA_MODEL.md`: this repo owns no persistent datastore (all domain data comes from the SDK at runtime)._
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Related context: [repository architecture](../../../ARCHITECTURE.md) · [specifi
| Work type | Defect |
| Change class | Contract / UI |
| Source/intake | Developer-approved consult/transfer behavior review and current code/tests |
| Last verified | 2026-08-24 with `@webex/contact-center` 3.12.0-next.106 |
| Last verified | 2026-08-25 with `@webex/contact-center` 3.12.0-next.109 |

## Applicability

Expand Down Expand Up @@ -68,7 +68,7 @@ There are no open product decisions for this delta.
- Load dial numbers through the generic SDK AddressBook service and rely on its default backend ordering.
- Preserve the SDK's `data` order and pagination metadata without local sorting, channel filtering, or metadata reconstruction.
- Keep loading, empty, and error behavior in the existing widget layers.
- Use the pinned `@webex/contact-center` 3.12.0-next.106 dependency containing the coordinated SDK change.
- Use the pinned `@webex/contact-center` 3.12.0-next.109 dependency containing the coordinated SDK change.

### Out of scope

Expand Down Expand Up @@ -142,11 +142,11 @@ There are no open product decisions for this delta.
- [x] Queue and entry-point fetchers delegate to existing SDK methods, while dial numbers use AddressBook, without local returned-data sort/filter/metadata logic (`MOD-001`, `WIDGET-LIST-R-001`, `WIDGET-LIST-R-004`).
- [x] Params-only telephony queue requests rely on SDK defaults; active non-telephony requests supply a complete channel filter, and legacy media-plus-params calls preserve their channel scope and caller filter. Entry-point requests always delegate directly, and no list request contains widget-selected sorting, projection, or profile-view flags (`MOD-001`, `WIDGET-LIST-R-003`).
- [x] Store errors are rethrown and task-hook errors retain the existing empty-result behavior (`WIDGET-LIST-R-005`).
- [x] Store, task, test-fixtures, and cc-components build/type surfaces agree with `@webex/contact-center` 3.12.0-next.106 (`WIDGET-LIST-R-006`).
- [x] Store, task, test-fixtures, and cc-components build/type surfaces agree with `@webex/contact-center` 3.12.0-next.109 (`WIDGET-LIST-R-006`).
- [x] Agent rows show active/away presence from buddy state, and dial-number/entry-point rows show their typed secondary identifiers (`WIDGET-LIST-R-008`).
- [x] A late buddy-agent response from a previous Consult/Transfer action cannot overwrite the current action's list or loading state (`WIDGET-LIST-R-009`).
- [x] Store and task unit suites, focused consult/transfer cc-components tests, and touched package build/style checks pass with `@webex/contact-center` 3.12.0-next.106.
- [x] The complete cc-components unit suite and the focused consult/transfer suites pass with `@webex/contact-center` 3.12.0-next.106.
- [x] Store and task unit suites, focused consult/transfer cc-components tests, and touched package build/style checks pass with `@webex/contact-center` 3.12.0-next.109.
- [x] The complete cc-components unit suite and the focused consult/transfer suites pass with `@webex/contact-center` 3.12.0-next.109.

## Scenarios and applicable change views

Expand Down Expand Up @@ -243,7 +243,7 @@ No event contract changes.

| Risk or assumption | Evidence | Mitigation or decision owner |
| --- | --- | --- |
| Widgets are run with an SDK lacking the corrected defaults and action-aware buddy policy. | `packages/contact-center/store/package.json` | Pin the store to the compatible SDK release; currently `3.12.0-next.106`. |
| Widgets are run with an SDK lacking the corrected defaults and action-aware buddy policy. | `packages/contact-center/store/package.json` | Pin the store to the compatible SDK release; currently `3.12.0-next.109`. |
| A future widget reintroduces local sorting/filtering. | `packages/contact-center/store/tests/storeEventsWrapper.ts` | Retain delegation and exact-response assertions. |
| Transfer action is lost during reload. | `packages/contact-center/cc-components/tests/components/task/CallControl/CallControlCustom/consult-transfer-popover.tsx` | Retain the action-specific reload assertion. |
| A Consult buddy request completes after the user switches to Transfer. | `packages/contact-center/task/src/helper.ts` | Track the newest buddy request and ignore older data, error fallback, and loading-state updates. |
Expand Down
Loading
Loading