@webex/contact-center 3.12.0-next.9 → 3.12.0-next.91

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/.sdd/manifest.json +876 -0
  2. package/AGENTS.md +94 -0
  3. package/ai-docs/ARCHITECTURE.md +168 -0
  4. package/ai-docs/CONTRACTS.md +46 -0
  5. package/ai-docs/GETTING_STARTED.md +168 -0
  6. package/ai-docs/GLOSSARY.md +43 -0
  7. package/ai-docs/README.md +138 -0
  8. package/ai-docs/REVIEW_CHECKLIST.md +41 -0
  9. package/ai-docs/RULES.md +444 -0
  10. package/ai-docs/SECURITY.md +52 -0
  11. package/ai-docs/SERVICE_STATE.md +48 -0
  12. package/ai-docs/SPEC_INDEX.md +65 -0
  13. package/ai-docs/adr/0001-spec-source-policy.md +55 -0
  14. package/ai-docs/adr/README.md +8 -0
  15. package/ai-docs/adr/_adr-template.md +31 -0
  16. package/ai-docs/contact-center-spec.md +341 -0
  17. package/ai-docs/features/generated-spec-conformance-fidelity-remediation/spec/feature-spec.md +117 -0
  18. package/ai-docs/features/residual-warning-coverage-completion/spec/feature-spec.md +203 -0
  19. package/ai-docs/features/validator-code-fidelity-drift-fix/spec/feature-spec.md +315 -0
  20. package/ai-docs/patterns/event-driven-patterns.md +485 -0
  21. package/ai-docs/patterns/testing-patterns.md +480 -0
  22. package/ai-docs/patterns/typescript-patterns.md +365 -0
  23. package/ai-docs/templates/README.md +102 -0
  24. package/ai-docs/templates/documentation/create-agents-md.md +240 -0
  25. package/ai-docs/templates/documentation/create-architecture-md.md +295 -0
  26. package/ai-docs/templates/existing-service/bug-fix.md +254 -0
  27. package/ai-docs/templates/existing-service/feature-enhancement.md +450 -0
  28. package/ai-docs/templates/new-method/00-master.md +80 -0
  29. package/ai-docs/templates/new-method/01-requirements.md +232 -0
  30. package/ai-docs/templates/new-method/02-implementation.md +295 -0
  31. package/ai-docs/templates/new-method/03-tests.md +201 -0
  32. package/ai-docs/templates/new-method/04-validation.md +141 -0
  33. package/ai-docs/templates/new-service/00-master.md +109 -0
  34. package/ai-docs/templates/new-service/01-pre-questions.md +159 -0
  35. package/ai-docs/templates/new-service/02-code-generation.md +346 -0
  36. package/ai-docs/templates/new-service/03-integration.md +178 -0
  37. package/ai-docs/templates/new-service/04-test-generation.md +205 -0
  38. package/ai-docs/templates/new-service/05-validation.md +145 -0
  39. package/dist/cc.js +265 -29
  40. package/dist/cc.js.map +1 -1
  41. package/dist/config.js +6 -0
  42. package/dist/config.js.map +1 -1
  43. package/dist/constants.js +17 -1
  44. package/dist/constants.js.map +1 -1
  45. package/dist/index.js +20 -5
  46. package/dist/index.js.map +1 -1
  47. package/dist/metrics/behavioral-events.js +101 -0
  48. package/dist/metrics/behavioral-events.js.map +1 -1
  49. package/dist/metrics/constants.js +25 -4
  50. package/dist/metrics/constants.js.map +1 -1
  51. package/dist/services/ApiAiAssistant.js +153 -8
  52. package/dist/services/ApiAiAssistant.js.map +1 -1
  53. package/dist/services/UserPreference.js +427 -0
  54. package/dist/services/UserPreference.js.map +1 -0
  55. package/dist/services/config/Util.js +3 -3
  56. package/dist/services/config/Util.js.map +1 -1
  57. package/dist/services/config/constants.js +23 -2
  58. package/dist/services/config/constants.js.map +1 -1
  59. package/dist/services/config/types.js +49 -9
  60. package/dist/services/config/types.js.map +1 -1
  61. package/dist/services/core/Err.js.map +1 -1
  62. package/dist/services/core/Utils.js +107 -32
  63. package/dist/services/core/Utils.js.map +1 -1
  64. package/dist/services/core/websocket/WebSocketManager.js +2 -1
  65. package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
  66. package/dist/services/core/websocket/types.js.map +1 -1
  67. package/dist/services/index.js +1 -1
  68. package/dist/services/index.js.map +1 -1
  69. package/dist/services/task/Task.js +688 -0
  70. package/dist/services/task/Task.js.map +1 -0
  71. package/dist/services/task/TaskFactory.js +45 -0
  72. package/dist/services/task/TaskFactory.js.map +1 -0
  73. package/dist/services/task/TaskManager.js +728 -527
  74. package/dist/services/task/TaskManager.js.map +1 -1
  75. package/dist/services/task/TaskUtils.js +162 -26
  76. package/dist/services/task/TaskUtils.js.map +1 -1
  77. package/dist/services/task/constants.js +9 -2
  78. package/dist/services/task/constants.js.map +1 -1
  79. package/dist/services/task/dialer.js +78 -0
  80. package/dist/services/task/dialer.js.map +1 -1
  81. package/dist/services/task/digital/Digital.js +77 -0
  82. package/dist/services/task/digital/Digital.js.map +1 -0
  83. package/dist/services/task/state-machine/TaskStateMachine.js +837 -0
  84. package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
  85. package/dist/services/task/state-machine/actions.js +543 -0
  86. package/dist/services/task/state-machine/actions.js.map +1 -0
  87. package/dist/services/task/state-machine/constants.js +161 -0
  88. package/dist/services/task/state-machine/constants.js.map +1 -0
  89. package/dist/services/task/state-machine/guards.js +340 -0
  90. package/dist/services/task/state-machine/guards.js.map +1 -0
  91. package/dist/services/task/state-machine/index.js +53 -0
  92. package/dist/services/task/state-machine/index.js.map +1 -0
  93. package/dist/services/task/state-machine/types.js +54 -0
  94. package/dist/services/task/state-machine/types.js.map +1 -0
  95. package/dist/services/task/state-machine/uiControlsComputer.js +553 -0
  96. package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
  97. package/dist/services/task/taskDataNormalizer.js +99 -0
  98. package/dist/services/task/taskDataNormalizer.js.map +1 -0
  99. package/dist/services/task/types.js +212 -4
  100. package/dist/services/task/types.js.map +1 -1
  101. package/dist/services/task/voice/Voice.js +1042 -0
  102. package/dist/services/task/voice/Voice.js.map +1 -0
  103. package/dist/services/task/voice/WebRTC.js +149 -0
  104. package/dist/services/task/voice/WebRTC.js.map +1 -0
  105. package/dist/types/cc.d.ts +94 -1
  106. package/dist/types/config.d.ts +6 -0
  107. package/dist/types/constants.d.ts +17 -1
  108. package/dist/types/index.d.ts +21 -6
  109. package/dist/types/metrics/constants.d.ts +21 -1
  110. package/dist/types/services/ApiAiAssistant.d.ts +22 -4
  111. package/dist/types/services/UserPreference.d.ts +118 -0
  112. package/dist/types/services/config/constants.d.ts +21 -0
  113. package/dist/types/services/config/types.d.ts +171 -10
  114. package/dist/types/services/core/Err.d.ts +4 -0
  115. package/dist/types/services/core/Utils.d.ts +33 -13
  116. package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -0
  117. package/dist/types/services/core/websocket/types.d.ts +1 -1
  118. package/dist/types/services/index.d.ts +1 -1
  119. package/dist/types/services/task/Task.d.ts +157 -0
  120. package/dist/types/services/task/TaskFactory.d.ts +12 -0
  121. package/dist/types/services/task/TaskUtils.d.ts +46 -2
  122. package/dist/types/services/task/constants.d.ts +7 -0
  123. package/dist/types/services/task/dialer.d.ts +30 -0
  124. package/dist/types/services/task/digital/Digital.d.ts +22 -0
  125. package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +1144 -0
  126. package/dist/types/services/task/state-machine/actions.d.ts +10 -0
  127. package/dist/types/services/task/state-machine/constants.d.ts +107 -0
  128. package/dist/types/services/task/state-machine/guards.d.ts +90 -0
  129. package/dist/types/services/task/state-machine/index.d.ts +13 -0
  130. package/dist/types/services/task/state-machine/types.d.ts +267 -0
  131. package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
  132. package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
  133. package/dist/types/services/task/types.d.ts +603 -66
  134. package/dist/types/services/task/voice/Voice.d.ts +184 -0
  135. package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
  136. package/dist/types/types.d.ts +135 -0
  137. package/dist/types/webex.d.ts +1 -0
  138. package/dist/types.js +118 -2
  139. package/dist/types.js.map +1 -1
  140. package/dist/webex.js +14 -2
  141. package/dist/webex.js.map +1 -1
  142. package/package.json +15 -12
  143. package/src/cc.ts +329 -30
  144. package/src/config.ts +6 -0
  145. package/src/constants.ts +17 -1
  146. package/src/index.ts +23 -5
  147. package/src/metrics/ai-docs/AGENTS.md +350 -0
  148. package/src/metrics/ai-docs/ARCHITECTURE.md +338 -0
  149. package/src/metrics/ai-docs/metrics-spec.md +854 -0
  150. package/src/metrics/behavioral-events.ts +106 -0
  151. package/src/metrics/constants.ts +27 -4
  152. package/src/services/ApiAiAssistant.ts +203 -8
  153. package/src/services/UserPreference.ts +509 -0
  154. package/src/services/agent/ai-docs/AGENTS.md +240 -0
  155. package/src/services/agent/ai-docs/ARCHITECTURE.md +304 -0
  156. package/src/services/agent/ai-docs/agent-spec.md +504 -0
  157. package/src/services/ai-docs/AGENTS.md +386 -0
  158. package/src/services/ai-docs/services-spec.md +492 -0
  159. package/src/services/config/Util.ts +3 -3
  160. package/src/services/config/ai-docs/AGENTS.md +255 -0
  161. package/src/services/config/ai-docs/ARCHITECTURE.md +426 -0
  162. package/src/services/config/ai-docs/config-spec.md +669 -0
  163. package/src/services/config/constants.ts +25 -1
  164. package/src/services/config/types.ts +174 -11
  165. package/src/services/core/Err.ts +2 -0
  166. package/src/services/core/Utils.ts +123 -37
  167. package/src/services/core/ai-docs/AGENTS.md +381 -0
  168. package/src/services/core/ai-docs/ARCHITECTURE.md +698 -0
  169. package/src/services/core/ai-docs/core-spec.md +783 -0
  170. package/src/services/core/websocket/WebSocketManager.ts +2 -0
  171. package/src/services/core/websocket/types.ts +1 -1
  172. package/src/services/index.ts +1 -1
  173. package/src/services/task/Task.ts +837 -0
  174. package/src/services/task/TaskFactory.ts +55 -0
  175. package/src/services/task/TaskManager.ts +739 -614
  176. package/src/services/task/TaskUtils.ts +205 -25
  177. package/src/services/task/ai-docs/AGENTS.md +457 -0
  178. package/src/services/task/ai-docs/ARCHITECTURE.md +594 -0
  179. package/src/services/task/ai-docs/task-spec.md +1319 -0
  180. package/src/services/task/constants.ts +7 -0
  181. package/src/services/task/dialer.ts +80 -0
  182. package/src/services/task/digital/Digital.ts +95 -0
  183. package/src/services/task/state-machine/TaskStateMachine.ts +1077 -0
  184. package/src/services/task/state-machine/actions.ts +685 -0
  185. package/src/services/task/state-machine/ai-docs/AGENTS.md +458 -0
  186. package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1137 -0
  187. package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +2115 -0
  188. package/src/services/task/state-machine/constants.ts +172 -0
  189. package/src/services/task/state-machine/guards.ts +406 -0
  190. package/src/services/task/state-machine/index.ts +28 -0
  191. package/src/services/task/state-machine/types.ts +241 -0
  192. package/src/services/task/state-machine/uiControlsComputer.ts +867 -0
  193. package/src/services/task/taskDataNormalizer.ts +137 -0
  194. package/src/services/task/types.ts +710 -71
  195. package/src/services/task/voice/Voice.ts +1267 -0
  196. package/src/services/task/voice/WebRTC.ts +187 -0
  197. package/src/types.ts +166 -2
  198. package/src/utils/AGENTS.md +278 -0
  199. package/src/utils/ai-docs/utils-spec.md +381 -0
  200. package/src/webex.js +2 -0
  201. package/test/unit/spec/cc.ts +343 -23
  202. package/test/unit/spec/logger-proxy.ts +70 -0
  203. package/test/unit/spec/services/ApiAiAssistant.ts +178 -20
  204. package/test/unit/spec/services/UserPreference.ts +401 -0
  205. package/test/unit/spec/services/WebCallingService.ts +7 -1
  206. package/test/unit/spec/services/config/index.ts +30 -30
  207. package/test/unit/spec/services/core/Utils.ts +425 -8
  208. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +66 -40
  209. package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
  210. package/test/unit/spec/services/task/Task.ts +477 -0
  211. package/test/unit/spec/services/task/TaskFactory.ts +62 -0
  212. package/test/unit/spec/services/task/TaskManager.ts +834 -1704
  213. package/test/unit/spec/services/task/TaskUtils.ts +206 -0
  214. package/test/unit/spec/services/task/dialer.ts +190 -0
  215. package/test/unit/spec/services/task/digital/Digital.ts +105 -0
  216. package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +1825 -0
  217. package/test/unit/spec/services/task/state-machine/guards.ts +479 -0
  218. package/test/unit/spec/services/task/state-machine/types.ts +18 -0
  219. package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +2020 -0
  220. package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
  221. package/test/unit/spec/services/task/voice/Voice.ts +631 -0
  222. package/test/unit/spec/services/task/voice/WebRTC.ts +235 -0
  223. package/umd/contact-center.min.js +2 -2
  224. package/umd/contact-center.min.js.map +1 -1
  225. package/dist/services/task/index.js +0 -1525
  226. package/dist/services/task/index.js.map +0 -1
  227. package/dist/types/services/task/index.d.ts +0 -650
  228. package/src/services/task/index.ts +0 -1801
  229. package/test/unit/spec/services/task/index.ts +0 -2184
@@ -0,0 +1,783 @@
1
+ # Core — SPEC
2
+
3
+ > Start here → root [`AGENTS.md`](../../../../AGENTS.md) · router [`SPEC_INDEX.md`](../../../../ai-docs/SPEC_INDEX.md) · system [`ARCHITECTURE.md`](../../../../ai-docs/ARCHITECTURE.md). This is the module's canonical specification.
4
+
5
+ ## Metadata
6
+
7
+ | Field | Value |
8
+ |---|---|
9
+ | Module id | `core` |
10
+ | Source path(s) | `src/services/core` |
11
+ | Doc kind | Module spec |
12
+ | Coverage score | Partial (manifest-authoritative); 15/15 required document fields present |
13
+ | Generated from | `module-spec` @ SDLC template library `0.2.1` |
14
+ | generated_by / approved_by / updated_at | Codex generator / developer-approved follow-up review remediation / 2026-07-21 |
15
+ | Validation status | Follow-up validation passed (independent Claude fallback, 2026-07-21); coverage remains Partial |
16
+
17
+ ## Evidence Rules
18
+ Every requirement cites stable source and test file paths. Code/tests are the behavioral referee; routed source text supplies explicit intent and rationale. Missing or contradictory evidence blocks promotion.
19
+
20
+ ## Source Material Register
21
+ | Source material | Scope | Decision | Detail location or disposition |
22
+ |---|---|---|---|
23
+ | Reviewed prior module guides and architecture material | overview / architecture / API / tests | used and code-checked | Content is placed by meaning throughout this specification; exact routing remains in the manifest. |
24
+
25
+ ## Overview
26
+ Core is one of nine confirmed Contact Center SDK modules. Own authenticated HTTP, realtime WebSocket lifecycle, AQM request correlation, reconnect/keepalive behavior, and shared error normalization. Existing reviewed documentation is migrated by meaning and code/tests remain the behavioral referee.
27
+
28
+ The Core service provides the foundational infrastructure layer that all other services depend on:
29
+
30
+ - **WebSocket Communication**: Real-time bidirectional messaging with the contact center backend, including automatic reconnection and keepalive management
31
+
32
+ - **HTTP Request Handling**: Authenticated REST API calls to WCC API Gateway with built-in error handling and log upload support
33
+
34
+ - **AQM Request/Response Pattern**: A structured pattern used by the routing and contact layers to send HTTP requests to the contact center backend and correlate responses/failures via WebSocket notifications
35
+
36
+ - **Error Handling & Logging**: Standardized error extraction, logging via `LoggerProxy`, and log upload utilities that all services use for consistent error reporting
37
+
38
+ | Component | File | Description |
39
+ |---|---|---|
40
+ | `WebSocketManager` | [`WebSocketManager.ts`](../websocket/WebSocketManager.ts) | Manages the WebSocket connection lifecycle including initialization, message dispatch, and graceful shutdown. Emits `message` events for incoming data and `socketClose` when the connection drops while reconnect is allowed. |
41
+ | `ConnectionService` | [`connection-service.ts`](../websocket/connection-service.ts) | Orchestrates reconnection logic and keepalive heartbeats on top of `WebSocketManager`. Detects connection loss/recovery and emits `connectionLost` details; ContactCenter owns any `silentRelogin()` policy. |
42
+ | `WebexRequest` | [`WebexRequest.ts`](../WebexRequest.ts) | Singleton HTTP client that forwards service/resource/method/body options to the authenticated host request API and provides `uploadLogs` diagnostics. |
43
+ | `AqmReqs` | [`aqm-reqs.ts`](../aqm-reqs.ts) | Factory for creating request methods that send HTTP requests and wait for correlated WebSocket notifications (success or failure). Used by routing and task services to implement their API methods. |
44
+ | `Utils` | [`Utils.ts`](../Utils.ts) | Shared utility functions including `getErrorDetails()` for standardized error handling, `generateTaskErrorObject()` for task-specific errors, and `createErrDetailsObject()` for constructing error detail objects. |
45
+ | `Err` | [`Err.ts`](../Err.ts) | Error class definitions. `Err.Details` carries structured error metadata (status, type, trackingId) for consistent error propagation. |
46
+ | `constants` | [`constants.ts`](../constants.ts) | Timeout values, interval durations, participant types, interaction states, and method name constants used throughout the core layer. Any new constants for core should be defined here. |
47
+
48
+ ## Purpose / Responsibility
49
+ Own authenticated HTTP, realtime WebSocket lifecycle, AQM request correlation, reconnect/keepalive behavior, and shared error normalization.
50
+
51
+ ## Stack
52
+ TypeScript/JavaScript, WebSocket, Web Worker keepalive, EventEmitter, Webex request client, Jest 27.
53
+
54
+ ## Folder / Package Structure
55
+ ```text
56
+ src/services/core/
57
+ ├── Err.ts
58
+ ├── GlobalTypes.ts
59
+ ├── Utils.ts
60
+ ├── WebexRequest.ts
61
+ ├── aqm-reqs.ts
62
+ ├── constants.ts
63
+ ├── types.ts
64
+ ├── websocket/
65
+ ```
66
+
67
+ ```text
68
+ services/core/
69
+ ├── aqm-reqs.ts # AQM request handler
70
+ ├── constants.ts # Core constants
71
+ ├── Err.ts # Error classes
72
+ ├── GlobalTypes.ts # Failure, Msg<T>, etc.
73
+ ├── types.ts # Request/response types
74
+ ├── Utils.ts # Utility functions
75
+ ├── WebexRequest.ts # HTTP client
76
+ └── websocket/
77
+ ├── WebSocketManager.ts # Main WS handler
78
+ ├── connection-service.ts # Connection lifecycle
79
+ ├── keepalive.worker.js # Keepalive worker
80
+ └── types.ts # WS types
81
+ ```
82
+
83
+ ## Key Files (source of truth)
84
+ | File | Holds |
85
+ |---|---|
86
+ | `src/services/core/WebexRequest.ts` | Authoritative Core implementation or contract source. |
87
+ | `src/services/core/aqm-reqs.ts` | Authoritative Core implementation or contract source. |
88
+ | `src/services/core/Utils.ts` | Authoritative Core implementation or contract source. |
89
+ | `src/services/core/Err.ts` | Authoritative Core implementation or contract source. |
90
+ | `src/services/core/websocket/WebSocketManager.ts` | Authoritative Core implementation or contract source. |
91
+ | `src/services/core/websocket/connection-service.ts` | Authoritative Core implementation or contract source. |
92
+
93
+ ## Public Surface
94
+ | Contract ID | Type | Surface | Purpose | Compatibility / deprecation | Schema / detail link | Root index |
95
+ |---|---|---|---|---|---|---|
96
+ | `core.surface` | SDK / event / internal API | Internal WebexRequest, WebSocketManager, ConnectionService, AqmReqs, and shared error/request types and helpers. | Stable module consumption boundary. | Additive changes by default; breaking package exports require a major-version transition. | `src/services/core/WebexRequest.ts` | `../../../../ai-docs/CONTRACTS.md` |
97
+
98
+ Compatibility notes:
99
+ - Do not remove or reinterpret exported symbols/events without a documented consumer migration.
100
+
101
+ | Event | Data | Description |
102
+ |---|---|---|
103
+ | `message` | string (JSON) | WebSocket message received |
104
+ | `socketClose` | - | Socket closed while reconnect is allowed |
105
+
106
+ Generic message wrapper used throughout the SDK. All WebSocket messages and AQM responses conform to this shape:
107
+
108
+ ```typescript
109
+ export type Msg<T = any> = {
110
+ type: string; // Message/Event type identifier
111
+ orgId: string; // Organization identifier
112
+ trackingId: string; // Unique tracking identifier
113
+ data: T; // Message/Event payload data
114
+ };
115
+
116
+ // Usage — the payload type goes into `data`
117
+ export type LoginSuccess = Msg<{
118
+ agentId: string;
119
+ status: string;
120
+ // ...
121
+ }>;
122
+ // Resulting shape: { type, orgId, trackingId, data: { agentId, status, ... } }
123
+ ```
124
+
125
+ ### ConnectionService internal surface — not public contracts
126
+
127
+ The only public method in the following list is `setConnectionProp`. The remaining methods are private implementation details documented for ownership and maintenance; they are not public API contracts.
128
+
129
+ 1. `setConnectionProp(prop: ConnectionProp): void` (public)
130
+
131
+ - **Purpose**: Updates connection-level runtime settings used by timers (mainly recovery timeout behavior).
132
+
133
+ - **Params**: `prop` - new connection config object.
134
+
135
+ - **Returns**: `void`.
136
+
137
+ - **Usage**: Called by higher layers when timeout behavior must be tuned after initialization.
138
+
139
+ 2. `setupEventListeners(): void` (private)
140
+
141
+ - **Purpose**: Wires `WebSocketManager` events to internal handlers (`'message' -> onPing`, `'socketClose' -> onSocketClose`).
142
+
143
+ - **Params**: none.
144
+
145
+ - **Returns**: `void`.
146
+
147
+ - **Usage**: Invoked from the constructor once, during `ConnectionService` setup.
148
+
149
+ 3. `onPing(event: any): void` (private)
150
+
151
+ - **Purpose**: Handles every incoming socket message, resets timers, updates keepalive/recovery flags, and emits recovery events when state changes.
152
+
153
+ - **Params**: `event` - raw message payload (JSON string) received from the socket event stream.
154
+
155
+ - **Returns**: `void`.
156
+
157
+ - **Usage**: Triggered automatically by the `'message'` listener.
158
+
159
+ 4. `onSocketClose(): void` (private)
160
+
161
+ - **Purpose**: Starts the reconnect interval when socket close is detected.
162
+
163
+ - **Params**: none.
164
+
165
+ - **Returns**: `void`.
166
+
167
+ - **Usage**: Triggered automatically by the `'socketClose'` listener.
168
+
169
+ 5. `handleSocketClose(): Promise<void>` (private)
170
+
171
+ - **Purpose**: Performs one reconnect attempt; if browser is online, reinitializes WebSocket and marks socket as reconnected.
172
+
173
+ - **Params**: none.
174
+
175
+ - **Returns**: `Promise<void>` (rejects when browser is offline).
176
+
177
+ - **Usage**: Called repeatedly from `onSocketClose` interval loop.
178
+
179
+ 6. `handleConnectionLost(): void` (private)
180
+
181
+ - **Purpose**: Marks the connection as lost and dispatches a connection status event.
182
+
183
+ - **Params**: none.
184
+
185
+ - **Returns**: `void`.
186
+
187
+ - **Usage**: Scheduled by `onPing` via `reconnectingTimer` after inactivity.
188
+
189
+ 7. `handleRestoreFailed(): Promise<void>` (private)
190
+
191
+ - **Purpose**: Marks restore as failed, disables reconnect, emits failure state, and clears reconnect interval.
192
+
193
+ - **Params**: none.
194
+
195
+ - **Returns**: `Promise<void>`.
196
+
197
+ - **Usage**: Scheduled by `onPing` via `restoreTimer`.
198
+
199
+ 8. `clearTimerOnRestoreFailed(): Promise<void>` (private)
200
+
201
+ - **Purpose**: Stops active reconnect interval to avoid duplicate retries.
202
+
203
+ - **Params**: none.
204
+
205
+ - **Returns**: `Promise<void>`.
206
+
207
+ - **Usage**: Called from reconnect/failure paths whenever interval cleanup is needed.
208
+
209
+ 9. `updateConnectionData(): void` (private)
210
+
211
+ - **Purpose**: Resets transient connection flags (`isConnectionLost`, `isRestoreFailed`, `isSocketReconnected`) after recovery.
212
+
213
+ - **Params**: none.
214
+
215
+ - **Returns**: `void`.
216
+
217
+ - **Usage**: Called inside `onPing` before dispatching recovered state.
218
+
219
+ 10. `dispatchConnectionEvent(socketReconnected = false): void` (private)
220
+
221
+ - **Purpose**: Builds `ConnectionLostDetails`, forwards it to `WebSocketManager.handleConnectionLost`, and emits `'connectionLost'`.
222
+
223
+ - **Params**: `socketReconnected` - optional override used when reconnect is explicitly detected.
224
+
225
+ - **Returns**: `void`.
226
+
227
+ - **Usage**: Used by lost/recovered/restore-failed paths to publish uniform connection state.
228
+
229
+ ```typescript
230
+ type ConnectionLostDetails = {
231
+ isConnectionLost: boolean;
232
+ isRestoreFailed: boolean;
233
+ isSocketReconnected: boolean;
234
+ isKeepAlive: boolean;
235
+ };
236
+
237
+ connectionService.on('connectionLost', (details: ConnectionLostDetails) => {
238
+ if (details.isConnectionLost) {
239
+ // Connection lost — waiting for recovery
240
+ } else if (details.isRestoreFailed) {
241
+ // Recovery timeout (50 s) exceeded
242
+ } else if (details.isSocketReconnected) {
243
+ // Socket successfully reconnected
244
+ }
245
+ });
246
+ ```
247
+
248
+ ## Requires (dependencies)
249
+ - Webex SDK service catalog and authenticated request API
250
+ - Browser WebSocket, Worker, URL and network-status APIs
251
+ - LoggerProxy and log upload
252
+
253
+ ## Requirements
254
+ | ID | WHAT | WHY | Source Evidence | Test / Example Evidence | Assumptions / Gaps | Confidence |
255
+ |---|---|---|---|---|---|---|
256
+ | CORE-R-001 | WebexRequest must delegate service/resource/method/body options to the authenticated host request API and return or reject with the host result unchanged. | All Contact Center REST clients share host-owned authentication and service routing without duplicating credential logic. | `src/services/core/WebexRequest.ts` | `test/unit/spec/services/core/WebexRequest.ts` | Authorization-header masking belongs to `AqmReqs` HTTP-failure handling, not `WebexRequest.request`. | PRESENT |
257
+ | CORE-R-002 | `initWebSocket` requires `{body: SubscribeRequest, resource: string}` and resolves only after WebSocket welcome or rejects on register/connect failure. | Subscription resource selection and readiness are required for a valid realtime session. | `src/services/core/websocket/WebSocketManager.ts` | `test/unit/spec/services/core/websocket/WebSocketManager.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
258
+ | CORE-R-003 | AqmReqs must be constructed with the primary WebSocket manager and settle generated request promises from `notifSuccess`/`notifFail` binds or `TIMEOUT_REQ`. | HTTP acknowledgement alone does not represent backend operation completion. | `src/services/core/aqm-reqs.ts` | `test/unit/spec/services/core/aqm-reqs.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
259
+ | CORE-R-004 | ConnectionService must emit transport-state details and retry `initWebSocket({body, resource})`; ContactCenter owns relogin policy. | Separating transport detection from agent recovery prevents Core from mutating package-level session state. | `src/services/core/websocket/connection-service.ts` | `test/unit/spec/services/core/websocket/connection-service.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
260
+ | CORE-R-005 | The keepalive worker must use the configured 4-second interval and 16-second close-socket timeout; AQM defaults to 20 seconds unless disabled/overridden. | Accurate timing is required for predictable recovery and request failure behavior. | `src/services/core/constants.ts` | `test/unit/spec/services/core/websocket/WebSocketManager.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
261
+ | CORE-R-006 | Treat Core timeout, keepalive, and recovery constants as fixed behavior controls, not rollout flags; Core owns no feature-gate evaluation. | Conflating operational constants with rollout policy could disable transport or correlation paths unexpectedly. | `src/services/core/constants.ts`, `src/services/index.ts` | `test/unit/spec/services/core/websocket/WebSocketManager.ts` | None; rollout applicability is explicitly N/A for Core. | PRESENT |
262
+
263
+ ## Design Overview
264
+ Core separates four responsibilities:
265
+
266
+ 1. `WebexRequest` wraps the authenticated host request API and service-catalog routing.
267
+ 2. `WebSocketManager` registers a subscription using both `body` and `resource`, connects the socket, owns the keepalive worker, and emits raw messages/socket lifecycle events.
268
+ 3. `AqmReqs` registers bind matchers on the primary WebSocket, sends HTTP through WebexRequest, and settles requests only from matching notifications, HTTP failure, or timeout.
269
+ 4. `ConnectionService` observes message/socket liveness, emits connection-state details, and retries socket initialization. ContactCenter listens to those details and owns optional silent relogin.
270
+
271
+ ```typescript
272
+ const aqmReqs = new AqmReqs(webSocketManager);
273
+ const setState = aqmReqs.req((p: {data: Agent.StateChange}) => ({
274
+ host: WCC_API_GATEWAY,
275
+ url: '/v1/agents/session/state',
276
+ data: p.data,
277
+ method: HTTP_METHODS.PUT,
278
+ notifSuccess: {
279
+ bind: {
280
+ type: CC_EVENTS.AGENT_STATE_CHANGE,
281
+ data: {type: CC_EVENTS.AGENT_STATE_CHANGE_SUCCESS},
282
+ },
283
+ msg: {} as Agent.StateChangeSuccess,
284
+ },
285
+ notifFail: {
286
+ bind: {
287
+ type: CC_EVENTS.AGENT_STATE_CHANGE,
288
+ data: {type: CC_EVENTS.AGENT_STATE_CHANGE_FAILED},
289
+ },
290
+ errId: 'Service.aqm.agent.stateChange',
291
+ },
292
+ }));
293
+ await setState({data: stateChangePayload});
294
+ ```
295
+
296
+ `CLOSE_SOCKET_TIMEOUT` is 16000 ms. `CONNECTIVITY_CHECK_INTERVAL` drives reconnect attempts separately. `TIMEOUT_REQ` is the 20000 ms default AQM timeout; `WEBSOCKET_EVENT_TIMEOUT` is not the active AqmReqs default.
297
+
298
+ ## Data Flow
299
+ ```mermaid
300
+ flowchart LR
301
+ Service[Agent/contact/dialer request] --> AQM[AqmReqs generated function]
302
+ AQM --> Bind[Register success/failure bind matchers]
303
+ AQM --> WR[WebexRequest authenticated HTTP]
304
+ WR --> Backend[WCC backend]
305
+ Backend --> Ack[HTTP acknowledgement]
306
+ Backend --> WS[Primary WebSocket notification]
307
+ WS --> Match{Bind matches?}
308
+ Match -->|success| Resolve[Resolve typed response]
309
+ Match -->|failure| Reject[Reject structured error]
310
+ Bind -->|TIMEOUT_REQ| Reject
311
+ ```
312
+
313
+ ```mermaid
314
+ flowchart TD
315
+ Message[WebSocket message] --> WSM[WebSocketManager emits message]
316
+ WSM --> CS[ConnectionService resets liveness timers]
317
+ CS --> Lost{Lost/recovered state changed?}
318
+ Lost -->|yes| Emit[Emit connectionLost details]
319
+ Emit --> CC[ContactCenter recovery policy]
320
+ SocketClose[Socket close] --> Retry[Retry every CONNECTIVITY_CHECK_INTERVAL]
321
+ Retry --> Init[initWebSocket body + SUBSCRIBE_API resource]
322
+ ```
323
+
324
+ ## Sequence Diagram(s)
325
+ Sequence coverage:
326
+
327
+ | Operation group | Diagram | Failure / recovery coverage |
328
+ |---|---|---|
329
+ | Authenticated REST | WebexRequest | Host/service rejection is propagated unchanged; AQM applies its own error mapping separately. |
330
+ | WebSocket subscribe/connect | Subscribe and connect | Register/connect rejection and welcome resolution. |
331
+ | AQM operation | Correlated request | Duplicate pending request, HTTP failure, failure bind, and timeout reject. |
332
+ | Reconnect | Connection recovery | Offline attempts retry on the next interval; restored and restore-failed states are emitted to ContactCenter. |
333
+
334
+ ### WebexRequest
335
+
336
+ ```mermaid
337
+ sequenceDiagram
338
+ participant Caller
339
+ participant WR as WebexRequest
340
+ participant Host as webex.request
341
+ participant API as WCC backend
342
+ Caller->>WR: request(service, resource, method, body)
343
+ WR->>Host: authenticated request(options)
344
+ Host->>API: HTTP request
345
+ alt success
346
+ API-->>Host: response
347
+ Host-->>WR: status/body/headers
348
+ WR-->>Caller: response
349
+ else host/service rejection
350
+ API-->>Host: error
351
+ Host-->>WR: same rejection
352
+ WR-->>Caller: same rejection
353
+ end
354
+ ```
355
+
356
+ ### Subscribe and connect
357
+
358
+ ```mermaid
359
+ sequenceDiagram
360
+ participant Caller
361
+ participant WSM as WebSocketManager
362
+ participant Host as webex.request
363
+ participant WS as Browser WebSocket
364
+ Caller->>WSM: initWebSocket({body, resource})
365
+ WSM->>Host: register(body, resource)
366
+ Host-->>WSM: WebSocket URL/subscription
367
+ WSM->>WS: connect()
368
+ alt welcome
369
+ WS-->>WSM: Welcome event
370
+ WSM-->>Caller: WelcomeResponse
371
+ else register/connect failure
372
+ WSM-->>Caller: throw error
373
+ end
374
+ ```
375
+
376
+ ### Correlated request
377
+
378
+ ```mermaid
379
+ sequenceDiagram
380
+ participant Caller
381
+ participant AQM as AqmReqs
382
+ participant WR as WebexRequest
383
+ participant WS as Primary WebSocket
384
+ Caller->>AQM: generated request(payload)
385
+ AQM->>AQM: install notifSuccess/notifFail matchers
386
+ alt matching pending request already exists and timeout is enabled
387
+ AQM-->>Caller: Service.aqm.reqs.Pending
388
+ else request accepted
389
+ AQM->>WR: request(config)
390
+ WR-->>AQM: HTTP acknowledgement only
391
+ alt success bind
392
+ WS-->>AQM: matching success notification
393
+ AQM-->>Caller: typed result
394
+ else failure bind or HTTP rejection
395
+ AQM-->>Caller: structured error
396
+ else timeout
397
+ AQM-->>Caller: Service.aqm.reqs.Timeout
398
+ end
399
+ end
400
+ ```
401
+
402
+ ### Connection recovery
403
+
404
+ ```mermaid
405
+ sequenceDiagram
406
+ participant WSM as WebSocketManager
407
+ participant CS as ConnectionService
408
+ participant CC as ContactCenter
409
+ WSM-->>CS: socketClose/message events
410
+ CS->>CS: update timers and reconnect state
411
+ alt browser online during retry interval
412
+ CS->>WSM: initWebSocket({body: subscribeRequest, resource: SUBSCRIBE_API})
413
+ WSM-->>CS: welcome/message
414
+ CS-->>CC: connectionLost({isSocketReconnected: true})
415
+ CC->>CC: decide whether to silentRelogin()
416
+ else browser offline or reconnect fails
417
+ CS->>CS: retain interval; retry on next CONNECTIVITY_CHECK_INTERVAL
418
+ opt recovery timeout expires
419
+ CS-->>CC: connectionLost({isRestoreFailed: true})
420
+ end
421
+ end
422
+ ```
423
+
424
+ ## Class / Component Relationships
425
+ ```mermaid
426
+ classDiagram
427
+ class WebexRequest
428
+ class WebSocketManager
429
+ class AqmReqs
430
+ class ConnectionService
431
+ class ContactCenter
432
+ AqmReqs --> WebexRequest : authenticated HTTP
433
+ AqmReqs --> WebSocketManager : bind-matched completion
434
+ ConnectionService --> WebSocketManager : liveness + reconnect
435
+ ConnectionService --> ContactCenter : connectionLost details
436
+ ContactCenter --> WebSocketManager : registration lifecycle
437
+ ```
438
+
439
+ ## Use Cases
440
+ - **UC-1 Authenticated REST:** pass the service key and request options to the host and return its response or rejection unchanged. Evidence: `src/services/core/WebexRequest.ts`, `test/unit/spec/services/core/WebexRequest.ts`.
441
+ - **UC-2 Subscribe/connect:** register with `{body, resource}`, connect, and wait for welcome. Evidence: `src/services/core/websocket/WebSocketManager.ts`, `test/unit/spec/services/core/websocket/WebSocketManager.ts`.
442
+ - **UC-3 AQM correlation:** send HTTP but settle on matching notification/failure/timeout. Evidence: `src/services/core/aqm-reqs.ts`, `test/unit/spec/services/core/aqm-reqs.ts`.
443
+ - **UC-4 Reconnect:** retry socket initialization and emit state for ContactCenter-owned recovery. Evidence: `src/services/core/websocket/connection-service.ts`, `test/unit/spec/services/core/websocket/connection-service.ts`.
444
+
445
+ ## State Model
446
+ WebSocketManager owns socket/welcome/worker state. AqmReqs owns pending success/failure/cancel bind maps until settlement or timeout. ConnectionService owns liveness/reconnect timers and flags, then emits state details. It does not own agent credentials, profile, or silent relogin.
447
+
448
+ ## Business Rules & Invariants
449
+ - Core must preserve its typed public/event contracts and must not invent backend states or responses. Enforced in `src/services/core/WebexRequest.ts`.
450
+ - Rollout applicability is N/A for Core: keepalive, timeout, and reconnect constants control behavior, while Services constructs Core without a feature gate.
451
+
452
+ ## Concurrency & Reactive Flow
453
+ The primary WebSocket fans messages to independent AqmReqs, ContactCenter, TaskManager, and ConnectionService listeners. AqmReqs clears all correlated bind entries on settlement. The keepalive worker posts status every 4000 ms and may request closure after 16000 ms offline; reconnect attempts use their separate interval. Listener registration/removal must preserve identity.
454
+
455
+ ## State Machine
456
+ ```mermaid
457
+ stateDiagram-v2
458
+ [*] --> SocketClosed
459
+ SocketClosed --> Connecting: initWebSocket(body, resource)
460
+ Connecting --> Connected: welcome
461
+ Connecting --> SocketClosed: register/connect error
462
+ Connected --> ConnectionSuspect: liveness timer expires
463
+ ConnectionSuspect --> Reconnecting: socket close / retry
464
+ Reconnecting --> Connected: reconnect + message
465
+ Reconnecting --> Reconnecting: offline or retry failure
466
+ Connected --> SocketClosed: manual close
467
+ ```
468
+
469
+ ## Protocol / Wire Format
470
+ `WebSocketManager.initWebSocket` accepts `{body: SubscribeRequest, resource: string}`. Subscription uses the host Webex request API; AqmReqs operational HTTP uses the WebexRequest wrapper. AQM request configs carry `host`, `url`, optional `method`/`data`, `notifSuccess.bind`, optional `notifFail.bind`, optional cancel bind, and optional timeout. HTTP acknowledgement never substitutes for the matching WebSocket operation result.
471
+
472
+ ## Error Handling & Failure Modes
473
+ | Condition | Signal (error/code/result) | Caller recovery |
474
+ |---|---|---|
475
+ | Dependency rejection | Typed/rethrown error or failure event | Inspect structured details, preserve tracking id, and retry only when the operation is safe. |
476
+ | Timeout or missing async completion | Timeout/recovery state | Follow the module-specific recovery path; never synthesize success. |
477
+
478
+ Standard error handler for SDK operations:
479
+
480
+ ```typescript
481
+ import {getErrorDetails} from './services/core/Utils';
482
+
483
+ try {
484
+ await operation();
485
+ } catch (error) {
486
+ const {error: detailedError, reason} = getErrorDetails(
487
+ error,
488
+ 'methodName', // Method name for logging
489
+ 'ModuleName' // Module name for logging
490
+ );
491
+
492
+ // getErrorDetails automatically:
493
+ // 1. Logs the error
494
+ // 2. Uploads logs (unless AGENT_NOT_FOUND in silentRelogin)
495
+ // 3. Extracts reason from error.details
496
+ // 4. Creates Error with reason as message
497
+
498
+ throw detailedError;
499
+ }
500
+ ```
501
+
502
+ Error handler for task operations:
503
+
504
+ ```typescript
505
+ import {generateTaskErrorObject} from './services/core/Utils';
506
+
507
+ try {
508
+ await taskOperation();
509
+ } catch (error) {
510
+ const taskError = generateTaskErrorObject(
511
+ error,
512
+ 'transfer',
513
+ 'TaskModule'
514
+ );
515
+ throw taskError;
516
+ }
517
+ ```
518
+
519
+ A specific `Msg<T>` for failure responses. Access error details via `failure.data`:
520
+
521
+ ```typescript
522
+ export type Failure = Msg<{
523
+ agentId: string;
524
+ trackingId: string;
525
+ reasonCode: number;
526
+ orgId: string;
527
+ reason: string;
528
+ }>;
529
+
530
+ // Usage in catch
531
+ const failure = error.details as Failure;
532
+ LoggerProxy.error(`Operation failed: ${failure.data?.reason}`, {
533
+ module: 'MyService',
534
+ method: 'myMethod',
535
+ trackingId: failure?.trackingId,
536
+ });
537
+ ```
538
+
539
+ Error interface with a flexible data field for additional context:
540
+
541
+ ```typescript
542
+ export interface AugmentedError extends Error {
543
+ data?: Record<string, any>;
544
+ }
545
+ ```
546
+
547
+ ```typescript
548
+ import * as Err from './Err';
549
+
550
+ const error = new Err.Details('Service.aqm.agent.login', {
551
+ status: 401,
552
+ type: 'UNAUTHORIZED',
553
+ trackingId: 'uuid',
554
+ });
555
+ ```
556
+
557
+ ```typescript
558
+ import {createErrDetailsObject} from './Utils';
559
+
560
+ const errDetails = createErrDetailsObject(webexRequestPayload);
561
+ // Returns Err.Details with trackingId and body
562
+ ```
563
+
564
+ ```typescript
565
+ // Correct
566
+ const {error: detailedError} = getErrorDetails(error, method, module);
567
+ throw detailedError;
568
+
569
+ // Wrong - loses context
570
+ throw error;
571
+ ```
572
+
573
+ This section documents shared error helpers in `Utils.ts` that normalize errors, enrich them with context, and ensure consistent logging/upload behavior across services.
574
+
575
+ ```typescript
576
+ // Msg - Generic message interface (GlobalTypes.ts)
577
+ export type Msg<T = any> = {
578
+ type: string;
579
+ orgId: string;
580
+ trackingId: string;
581
+ data: T;
582
+ };
583
+
584
+ // Failure - Backend error structure (GlobalTypes.ts)
585
+ // Built on Msg<T> with specific error data fields
586
+ export type Failure = Msg<{
587
+ agentId: string;
588
+ trackingId: string;
589
+ reasonCode: number;
590
+ orgId: string;
591
+ reason: string;
592
+ }>;
593
+
594
+ // AugmentedError - Extended Error with flexible data field (GlobalTypes.ts)
595
+ export interface AugmentedError extends Error {
596
+ data?: Record<string, any>;
597
+ }
598
+ ```
599
+
600
+ ```mermaid
601
+ flowchart TD
602
+ A[Error caught] --> B[Cast error.details to Failure]
603
+ B --> C[Extract reason from failure.data.reason]
604
+ C --> D{Is silentRelogin + AGENT_NOT_FOUND?}
605
+ D -->|Yes| E[Skip logging/upload]
606
+ D -->|No| F[Log error with LoggerProxy]
607
+ F --> G[Upload logs via WebexRequest]
608
+ G --> H[Check if stationLogin]
609
+ H -->|Yes| I[Get field-specific error data]
610
+ H -->|No| J[Use generic error]
611
+ I --> K[Create Error with data property]
612
+ J --> K
613
+ K --> L["Return {error, reason}"]
614
+ ```
615
+
616
+ Use this helper for agent/config-style flows where backend failure payloads are transformed into a user-facing `Error` plus `reason`, with optional station-login field metadata.
617
+
618
+ ```typescript
619
+ export const getErrorDetails = (error: any, methodName: string, moduleName: string) => {
620
+ let errData = {message: '', fieldName: ''};
621
+
622
+ const failure = error.details as Failure;
623
+ const reason = failure?.data?.reason ?? `Error while performing ${methodName}`;
624
+
625
+ // Log error (unless AGENT_NOT_FOUND in silentRelogin)
626
+ if (!(reason === 'AGENT_NOT_FOUND' && methodName === 'silentRelogin')) {
627
+ LoggerProxy.error(`${methodName} failed with reason: ${reason}`, {
628
+ module: moduleName,
629
+ method: methodName,
630
+ trackingId: failure?.trackingId,
631
+ });
632
+
633
+ // Upload logs
634
+ WebexRequest.getInstance().uploadLogs({
635
+ correlationId: failure?.trackingId,
636
+ });
637
+ }
638
+
639
+ // For stationLogin, extract field-specific error data (message + fieldName)
640
+ if (methodName === 'stationLogin') {
641
+ errData = getStationLoginErrorData(failure, error.loginOption);
642
+ }
643
+
644
+ const err = new Error(reason);
645
+ // @ts-ignore - custom property for backward compatibility
646
+ err.data = errData;
647
+
648
+ return {error: err, reason};
649
+ };
650
+ ```
651
+
652
+ Use this helper for task/interaction flows where richer task error metadata (`errorType`, `errorData`, `reasonCode`, `trackingId`) is required on the returned `AugmentedError`.
653
+
654
+ ```typescript
655
+ export const generateTaskErrorObject = (
656
+ error: any,
657
+ methodName: string,
658
+ moduleName: string
659
+ ): AugmentedError => {
660
+ const trackingId = error?.details?.trackingId || error?.trackingId || '';
661
+ const errorMsg = error?.details?.msg;
662
+
663
+ const errorMessage = errorMsg?.errorMessage || error.message || 'Error';
664
+ const errorType = errorMsg?.errorType || error.name || 'Unknown Error';
665
+ const errorData = errorMsg?.errorData || '';
666
+ const reasonCode = errorMsg?.reasonCode || 0;
667
+
668
+ LoggerProxy.error(`${methodName} failed: ${errorMessage} (${errorType})`, {
669
+ module: moduleName,
670
+ method: methodName,
671
+ trackingId,
672
+ });
673
+ WebexRequest.getInstance().uploadLogs({correlationId: trackingId});
674
+
675
+ const reason = `${errorType}: ${errorMessage}${errorData ? ` (${errorData})` : ''}`;
676
+ const err: AugmentedError = new Error(reason);
677
+ err.data = {
678
+ message: errorMessage,
679
+ errorType,
680
+ errorData,
681
+ reasonCode,
682
+ trackingId,
683
+ };
684
+
685
+ return err;
686
+ };
687
+ ```
688
+
689
+ ```typescript
690
+ // Use getErrorDetails for:
691
+ // - Agent service operations
692
+ // - Station login/logout flows
693
+ //
694
+ // Use generateTaskErrorObject for:
695
+ // - Task service operations
696
+ // - Interaction-related errors
697
+ ```
698
+
699
+ **Cause**: Subscribe API failed or invalid URL
700
+
701
+ **Solution**: Check subscribe response and WebSocket URL
702
+
703
+ **Cause**: Event listener not registered
704
+
705
+ **Solution**: Ensure `on('message', handler)` called before connect
706
+
707
+ **Cause**: Keepalive not enabled or network issues
708
+
709
+ **Solution**: Verify worker-driven keepalive is running after socket `onopen`, and check network/offline transitions
710
+
711
+ ## Pitfalls
712
+ - `initWebSocket` requires both `body` and `resource`; omitting `resource` registers against no durable subscription endpoint.
713
+ - AqmReqs installs notification binds before HTTP and never resolves from acknowledgement; duplicate binds, timeout, and cleanup ordering are correctness-critical.
714
+ - Keepalive closure (16 seconds), lost-connection detection (8 seconds), reconnect interval (5 seconds), and recovery timeout (50 seconds) are separate controls and must not be conflated.
715
+
716
+ ## Module Do's / Don'ts
717
+ - DO keep authentication and service resolution in the host Webex request layer; `WebexRequest.request` is a thin delegating wrapper.
718
+ - DO mask authorization headers in the `AqmReqs` HTTP-error/timeout paths before those details are logged or surfaced.
719
+ - DO clear success/failure/cancel bind entries together when an AQM request settles.
720
+ - DON'T move silent-relogin policy into ConnectionService; it emits transport state only.
721
+ - DON'T treat timeout constants as feature flags or reuse one timer for another lifecycle purpose.
722
+
723
+ ```typescript
724
+ const response = await webexReq.request({...});
725
+
726
+ if (response.statusCode !== 200) {
727
+ throw new Error(`API call failed with ${response.statusCode}`);
728
+ }
729
+ ```
730
+
731
+ ```typescript
732
+ const trackingId = response.headers?.trackingid ||
733
+ response.headers?.TrackingID;
734
+ ```
735
+
736
+ ## Key Design Trade-off
737
+ - Request initiation stays HTTP while completion can arrive asynchronously over WebSocket; explicit timers and correlation preserve backend fidelity but increase lifecycle complexity.
738
+
739
+ ## Test-Case Strategy (module)
740
+ Unit tests mirror module paths under `test/unit/spec/services/core`. Preserve positive and negative paths, event ordering, timeout/recovery behavior, and the package's 85% global branch/function/line/statement threshold.
741
+
742
+ | Behavior / Requirement | Existing test evidence | Gap |
743
+ |---|---|---|
744
+ | `CORE-R-001` | `test/unit/spec/services/core/WebexRequest.ts` | None. |
745
+ | `CORE-R-002` | `test/unit/spec/services/core/websocket/WebSocketManager.ts` | None. |
746
+ | `CORE-R-003` | `test/unit/spec/services/core/aqm-reqs.ts` | None. |
747
+ | `CORE-R-004` | `test/unit/spec/services/core/websocket/connection-service.ts` | None. |
748
+ | `CORE-R-005` | `test/unit/spec/services/core/websocket/WebSocketManager.ts` | Keep timer-value assertions synchronized with constants. |
749
+ | `CORE-R-006` | `test/unit/spec/services/core/websocket/WebSocketManager.ts` | Feature-gate absence is verified from construction/source rather than a dedicated negative test. |
750
+
751
+ ## Traceability
752
+ - Repo architecture: `../../../../ai-docs/ARCHITECTURE.md` · Registry: `../../../../ai-docs/SPEC_INDEX.md`
753
+ - Coverage state and contracts baseline: `../../../../.sdd/manifest.json`
754
+
755
+ - [Root Orchestrator AGENTS.md](../../../../AGENTS.md) - Task routing, critical rules, cross-service patterns
756
+
757
+ - [WebSocketManager.ts](../websocket/WebSocketManager.ts)
758
+
759
+ - [WebexRequest.ts](../WebexRequest.ts)
760
+
761
+ - [Utils.ts](../Utils.ts)
762
+
763
+ - [GlobalTypes.ts](../GlobalTypes.ts)
764
+
765
+ - [Root Orchestrator AGENTS.md](../../../../AGENTS.md) — Task routing, critical rules, cross-service patterns
766
+
767
+ - [WebSocketManager.ts](../websocket/WebSocketManager.ts) — WebSocket lifecycle, keepalive worker integration
768
+
769
+ - [connection-service.ts](../websocket/connection-service.ts) — Reconnection logic, connection state events
770
+
771
+ - [keepalive.worker.js](../websocket/keepalive.worker.js) — Web Worker for periodic keepalive and offline detection
772
+
773
+ - [WebexRequest.ts](../WebexRequest.ts) — Singleton HTTP request handler
774
+
775
+ - [Utils.ts](../Utils.ts) — `getErrorDetails`, `generateTaskErrorObject`, consult utilities
776
+
777
+ - [Err.ts](../Err.ts) — `Err.Message` and `Err.Details` error classes
778
+
779
+ - [aqm-reqs.ts](../aqm-reqs.ts) — AQM request/response pattern, WebSocket notification binding
780
+
781
+ - [GlobalTypes.ts](../GlobalTypes.ts) — `Msg`, `Failure`, `AugmentedError` type definitions
782
+
783
+ - [types.ts](../types.ts) — `Pending`, `Req`, `Conf`, `Res` types for AqmReqs