@webex/contact-center 3.11.0 → 3.12.0-auth-prejoin-fetch.1

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 (325) hide show
  1. package/.sdd/manifest.json +883 -0
  2. package/AGENTS.md +94 -0
  3. package/ai-docs/ARCHITECTURE.md +168 -0
  4. package/ai-docs/CONTRACTS.md +50 -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 +359 -0
  17. package/ai-docs/features/consult-transfer-list-policy/spec/feature-spec.md +362 -0
  18. package/ai-docs/features/generated-spec-conformance-fidelity-remediation/spec/feature-spec.md +117 -0
  19. package/ai-docs/features/residual-warning-coverage-completion/spec/feature-spec.md +203 -0
  20. package/ai-docs/features/validator-code-fidelity-drift-fix/spec/feature-spec.md +315 -0
  21. package/ai-docs/patterns/event-driven-patterns.md +485 -0
  22. package/ai-docs/patterns/testing-patterns.md +480 -0
  23. package/ai-docs/patterns/typescript-patterns.md +365 -0
  24. package/ai-docs/templates/README.md +102 -0
  25. package/ai-docs/templates/documentation/create-agents-md.md +240 -0
  26. package/ai-docs/templates/documentation/create-architecture-md.md +295 -0
  27. package/ai-docs/templates/existing-service/bug-fix.md +254 -0
  28. package/ai-docs/templates/existing-service/feature-enhancement.md +450 -0
  29. package/ai-docs/templates/new-method/00-master.md +80 -0
  30. package/ai-docs/templates/new-method/01-requirements.md +232 -0
  31. package/ai-docs/templates/new-method/02-implementation.md +295 -0
  32. package/ai-docs/templates/new-method/03-tests.md +201 -0
  33. package/ai-docs/templates/new-method/04-validation.md +141 -0
  34. package/ai-docs/templates/new-service/00-master.md +109 -0
  35. package/ai-docs/templates/new-service/01-pre-questions.md +159 -0
  36. package/ai-docs/templates/new-service/02-code-generation.md +346 -0
  37. package/ai-docs/templates/new-service/03-integration.md +178 -0
  38. package/ai-docs/templates/new-service/04-test-generation.md +205 -0
  39. package/ai-docs/templates/new-service/05-validation.md +145 -0
  40. package/dist/cc.js +818 -59
  41. package/dist/cc.js.map +1 -1
  42. package/dist/config.js +13 -0
  43. package/dist/config.js.map +1 -1
  44. package/dist/constants.js +31 -3
  45. package/dist/constants.js.map +1 -1
  46. package/dist/index.js +27 -5
  47. package/dist/index.js.map +1 -1
  48. package/dist/metrics/behavioral-events.js +127 -0
  49. package/dist/metrics/behavioral-events.js.map +1 -1
  50. package/dist/metrics/constants.js +34 -3
  51. package/dist/metrics/constants.js.map +1 -1
  52. package/dist/services/AddressBook.js +18 -15
  53. package/dist/services/AddressBook.js.map +1 -1
  54. package/dist/services/AnswerCallOnWebexService.js +174 -0
  55. package/dist/services/AnswerCallOnWebexService.js.map +1 -0
  56. package/dist/services/ApiAiAssistant.js +318 -0
  57. package/dist/services/ApiAiAssistant.js.map +1 -0
  58. package/dist/services/EntryPoint.js +46 -68
  59. package/dist/services/EntryPoint.js.map +1 -1
  60. package/dist/services/Queue.js +27 -22
  61. package/dist/services/Queue.js.map +1 -1
  62. package/dist/services/UserPreference.js +427 -0
  63. package/dist/services/UserPreference.js.map +1 -0
  64. package/dist/services/WebexCrossClientService.js +171 -0
  65. package/dist/services/WebexCrossClientService.js.map +1 -0
  66. package/dist/services/WxAppTelephonyMercurySync.js +93 -0
  67. package/dist/services/WxAppTelephonyMercurySync.js.map +1 -0
  68. package/dist/services/agent/types.js.map +1 -1
  69. package/dist/services/config/Util.js +11 -4
  70. package/dist/services/config/Util.js.map +1 -1
  71. package/dist/services/config/constants.js +45 -8
  72. package/dist/services/config/constants.js.map +1 -1
  73. package/dist/services/config/index.js +41 -2
  74. package/dist/services/config/index.js.map +1 -1
  75. package/dist/services/config/types.js +70 -8
  76. package/dist/services/config/types.js.map +1 -1
  77. package/dist/services/constants.js +27 -1
  78. package/dist/services/constants.js.map +1 -1
  79. package/dist/services/core/Err.js.map +1 -1
  80. package/dist/services/core/Utils.js +122 -25
  81. package/dist/services/core/Utils.js.map +1 -1
  82. package/dist/services/core/WebexRequest.js +6 -2
  83. package/dist/services/core/WebexRequest.js.map +1 -1
  84. package/dist/services/core/aqm-reqs.js +119 -30
  85. package/dist/services/core/aqm-reqs.js.map +1 -1
  86. package/dist/services/core/types.js.map +1 -1
  87. package/dist/services/core/websocket/WebSocketManager.js +22 -6
  88. package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
  89. package/dist/services/core/websocket/connection-service.js +3 -1
  90. package/dist/services/core/websocket/connection-service.js.map +1 -1
  91. package/dist/services/core/websocket/types.js.map +1 -1
  92. package/dist/services/index.js +6 -0
  93. package/dist/services/index.js.map +1 -1
  94. package/dist/services/task/Task.js +754 -0
  95. package/dist/services/task/Task.js.map +1 -0
  96. package/dist/services/task/TaskFactory.js +49 -0
  97. package/dist/services/task/TaskFactory.js.map +1 -0
  98. package/dist/services/task/TaskManager.js +1073 -447
  99. package/dist/services/task/TaskManager.js.map +1 -1
  100. package/dist/services/task/TaskUtils.js +220 -23
  101. package/dist/services/task/TaskUtils.js.map +1 -1
  102. package/dist/services/task/WebexCallingUtils.js +70 -0
  103. package/dist/services/task/WebexCallingUtils.js.map +1 -0
  104. package/dist/services/task/constants.js +26 -2
  105. package/dist/services/task/constants.js.map +1 -1
  106. package/dist/services/task/contact.js +29 -0
  107. package/dist/services/task/contact.js.map +1 -1
  108. package/dist/services/task/dialer.js +129 -0
  109. package/dist/services/task/dialer.js.map +1 -1
  110. package/dist/services/task/digital/Digital.js +78 -0
  111. package/dist/services/task/digital/Digital.js.map +1 -0
  112. package/dist/services/task/state-machine/TaskStateMachine.js +971 -0
  113. package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
  114. package/dist/services/task/state-machine/actions.js +572 -0
  115. package/dist/services/task/state-machine/actions.js.map +1 -0
  116. package/dist/services/task/state-machine/constants.js +161 -0
  117. package/dist/services/task/state-machine/constants.js.map +1 -0
  118. package/dist/services/task/state-machine/guards.js +409 -0
  119. package/dist/services/task/state-machine/guards.js.map +1 -0
  120. package/dist/services/task/state-machine/index.js +53 -0
  121. package/dist/services/task/state-machine/index.js.map +1 -0
  122. package/dist/services/task/state-machine/types.js +54 -0
  123. package/dist/services/task/state-machine/types.js.map +1 -0
  124. package/dist/services/task/state-machine/uiControlsComputer.js +703 -0
  125. package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
  126. package/dist/services/task/taskDataNormalizer.js +99 -0
  127. package/dist/services/task/taskDataNormalizer.js.map +1 -0
  128. package/dist/services/task/types.js +243 -5
  129. package/dist/services/task/types.js.map +1 -1
  130. package/dist/services/task/voice/Voice.js +1380 -0
  131. package/dist/services/task/voice/Voice.js.map +1 -0
  132. package/dist/services/task/voice/WebRTC.js +152 -0
  133. package/dist/services/task/voice/WebRTC.js.map +1 -0
  134. package/dist/services/task/voice/wxAppVoiceMethods.js +201 -0
  135. package/dist/services/task/voice/wxAppVoiceMethods.js.map +1 -0
  136. package/dist/services/wxAppTelephonyUtils.js +19 -0
  137. package/dist/services/wxAppTelephonyUtils.js.map +1 -0
  138. package/dist/types/cc.d.ts +967 -0
  139. package/dist/types/config.d.ts +79 -0
  140. package/dist/types/constants.d.ts +74 -0
  141. package/dist/types/index.d.ts +201 -0
  142. package/dist/types/logger-proxy.d.ts +71 -0
  143. package/dist/types/metrics/MetricsManager.d.ts +223 -0
  144. package/dist/types/metrics/behavioral-events.d.ts +29 -0
  145. package/dist/types/metrics/constants.d.ts +183 -0
  146. package/dist/types/services/AddressBook.d.ts +75 -0
  147. package/dist/types/services/AnswerCallOnWebexService.d.ts +37 -0
  148. package/dist/types/services/ApiAiAssistant.d.ts +49 -0
  149. package/dist/types/services/EntryPoint.d.ts +69 -0
  150. package/dist/types/services/Queue.d.ts +78 -0
  151. package/dist/types/services/UserPreference.d.ts +118 -0
  152. package/dist/types/services/WebCallingService.d.ts +1 -0
  153. package/dist/types/services/WebexCrossClientService.d.ts +28 -0
  154. package/dist/types/services/WxAppTelephonyMercurySync.d.ts +28 -0
  155. package/dist/types/services/agent/index.d.ts +46 -0
  156. package/dist/types/services/agent/types.d.ts +413 -0
  157. package/dist/types/services/config/Util.d.ts +20 -0
  158. package/dist/types/services/config/constants.d.ts +273 -0
  159. package/dist/types/services/config/index.d.ts +177 -0
  160. package/dist/types/services/config/types.d.ts +1381 -0
  161. package/dist/types/services/constants.d.ts +110 -0
  162. package/dist/types/services/core/Err.d.ts +127 -0
  163. package/dist/types/services/core/GlobalTypes.d.ts +58 -0
  164. package/dist/types/services/core/Utils.d.ts +121 -0
  165. package/dist/types/services/core/WebexRequest.d.ts +23 -0
  166. package/dist/types/services/core/aqm-reqs.d.ts +65 -0
  167. package/dist/types/services/core/constants.d.ts +99 -0
  168. package/dist/types/services/core/types.d.ts +49 -0
  169. package/dist/types/services/core/websocket/WebSocketManager.d.ts +36 -0
  170. package/dist/types/services/core/websocket/connection-service.d.ts +27 -0
  171. package/dist/types/services/core/websocket/keepalive.worker.d.ts +2 -0
  172. package/dist/types/services/core/websocket/types.d.ts +37 -0
  173. package/dist/types/services/index.d.ts +54 -0
  174. package/dist/types/services/task/AutoWrapup.d.ts +40 -0
  175. package/dist/types/services/task/Task.d.ts +175 -0
  176. package/dist/types/services/task/TaskFactory.d.ts +13 -0
  177. package/dist/types/services/task/TaskManager.d.ts +1 -0
  178. package/dist/types/services/task/TaskUtils.d.ts +138 -0
  179. package/dist/types/services/task/WebexCallingUtils.d.ts +11 -0
  180. package/dist/types/services/task/constants.d.ts +94 -0
  181. package/dist/types/services/task/contact.d.ts +73 -0
  182. package/dist/types/services/task/dialer.d.ts +73 -0
  183. package/dist/types/services/task/digital/Digital.d.ts +22 -0
  184. package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +1398 -0
  185. package/dist/types/services/task/state-machine/actions.d.ts +10 -0
  186. package/dist/types/services/task/state-machine/constants.d.ts +107 -0
  187. package/dist/types/services/task/state-machine/guards.d.ts +103 -0
  188. package/dist/types/services/task/state-machine/index.d.ts +13 -0
  189. package/dist/types/services/task/state-machine/types.d.ts +277 -0
  190. package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
  191. package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
  192. package/dist/types/services/task/types.d.ts +1933 -0
  193. package/dist/types/services/task/voice/Voice.d.ts +223 -0
  194. package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
  195. package/dist/types/services/task/voice/wxAppVoiceMethods.d.ts +52 -0
  196. package/dist/types/services/wxAppTelephonyUtils.d.ts +5 -0
  197. package/dist/types/types.d.ts +784 -0
  198. package/dist/types/utils/PageCache.d.ts +190 -0
  199. package/dist/types/webex-config.d.ts +53 -0
  200. package/dist/types/webex.d.ts +8 -0
  201. package/dist/types.js +137 -3
  202. package/dist/types.js.map +1 -1
  203. package/dist/utils/PageCache.js +19 -5
  204. package/dist/utils/PageCache.js.map +1 -1
  205. package/dist/webex.js +14 -2
  206. package/dist/webex.js.map +1 -1
  207. package/package.json +16 -12
  208. package/src/cc.ts +983 -60
  209. package/src/config.ts +13 -0
  210. package/src/constants.ts +29 -1
  211. package/src/index.ts +26 -5
  212. package/src/metrics/ai-docs/AGENTS.md +350 -0
  213. package/src/metrics/ai-docs/ARCHITECTURE.md +338 -0
  214. package/src/metrics/ai-docs/metrics-spec.md +860 -0
  215. package/src/metrics/behavioral-events.ts +134 -0
  216. package/src/metrics/constants.ts +39 -3
  217. package/src/services/AddressBook.ts +17 -6
  218. package/src/services/AnswerCallOnWebexService.ts +206 -0
  219. package/src/services/ApiAiAssistant.ts +412 -0
  220. package/src/services/EntryPoint.ts +59 -60
  221. package/src/services/Queue.ts +29 -12
  222. package/src/services/UserPreference.ts +509 -0
  223. package/src/services/WebexCrossClientService.ts +212 -0
  224. package/src/services/WxAppTelephonyMercurySync.ts +115 -0
  225. package/src/services/agent/ai-docs/AGENTS.md +240 -0
  226. package/src/services/agent/ai-docs/ARCHITECTURE.md +304 -0
  227. package/src/services/agent/ai-docs/agent-spec.md +504 -0
  228. package/src/services/agent/types.ts +1 -1
  229. package/src/services/ai-docs/AGENTS.md +386 -0
  230. package/src/services/ai-docs/services-spec.md +497 -0
  231. package/src/services/config/Util.ts +13 -2
  232. package/src/services/config/ai-docs/AGENTS.md +255 -0
  233. package/src/services/config/ai-docs/ARCHITECTURE.md +426 -0
  234. package/src/services/config/ai-docs/config-spec.md +675 -0
  235. package/src/services/config/constants.ts +47 -7
  236. package/src/services/config/index.ts +45 -1
  237. package/src/services/config/types.ts +253 -11
  238. package/src/services/constants.ts +29 -0
  239. package/src/services/core/Err.ts +4 -0
  240. package/src/services/core/Utils.ts +143 -30
  241. package/src/services/core/WebexRequest.ts +3 -1
  242. package/src/services/core/ai-docs/AGENTS.md +381 -0
  243. package/src/services/core/ai-docs/ARCHITECTURE.md +698 -0
  244. package/src/services/core/ai-docs/core-spec.md +787 -0
  245. package/src/services/core/aqm-reqs.ts +125 -32
  246. package/src/services/core/types.ts +2 -0
  247. package/src/services/core/websocket/WebSocketManager.ts +23 -6
  248. package/src/services/core/websocket/connection-service.ts +5 -1
  249. package/src/services/core/websocket/types.ts +1 -1
  250. package/src/services/index.ts +4 -0
  251. package/src/services/task/Task.ts +908 -0
  252. package/src/services/task/TaskFactory.ts +60 -0
  253. package/src/services/task/TaskManager.ts +1291 -513
  254. package/src/services/task/TaskUtils.ts +314 -24
  255. package/src/services/task/WebexCallingUtils.ts +136 -0
  256. package/src/services/task/ai-docs/AGENTS.md +457 -0
  257. package/src/services/task/ai-docs/ARCHITECTURE.md +595 -0
  258. package/src/services/task/ai-docs/task-spec.md +1469 -0
  259. package/src/services/task/constants.ts +26 -0
  260. package/src/services/task/contact.ts +30 -0
  261. package/src/services/task/dialer.ts +136 -1
  262. package/src/services/task/digital/Digital.ts +97 -0
  263. package/src/services/task/state-machine/TaskStateMachine.ts +1313 -0
  264. package/src/services/task/state-machine/actions.ts +741 -0
  265. package/src/services/task/state-machine/ai-docs/AGENTS.md +462 -0
  266. package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1146 -0
  267. package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +2209 -0
  268. package/src/services/task/state-machine/constants.ts +172 -0
  269. package/src/services/task/state-machine/guards.ts +498 -0
  270. package/src/services/task/state-machine/index.ts +28 -0
  271. package/src/services/task/state-machine/types.ts +258 -0
  272. package/src/services/task/state-machine/uiControlsComputer.ts +1135 -0
  273. package/src/services/task/taskDataNormalizer.ts +137 -0
  274. package/src/services/task/types.ts +843 -70
  275. package/src/services/task/voice/Voice.ts +1720 -0
  276. package/src/services/task/voice/WebRTC.ts +191 -0
  277. package/src/services/task/voice/wxAppVoiceMethods.ts +307 -0
  278. package/src/services/wxAppTelephonyUtils.ts +14 -0
  279. package/src/types.ts +238 -11
  280. package/src/utils/AGENTS.md +289 -0
  281. package/src/utils/PageCache.ts +38 -5
  282. package/src/utils/ai-docs/utils-spec.md +391 -0
  283. package/src/webex.js +2 -0
  284. package/test/unit/spec/cc.ts +1856 -122
  285. package/test/unit/spec/logger-proxy.ts +70 -0
  286. package/test/unit/spec/metrics/behavioral-events.ts +18 -0
  287. package/test/unit/spec/services/AddressBook.ts +37 -6
  288. package/test/unit/spec/services/AnswerCallOnWebexService.ts +223 -0
  289. package/test/unit/spec/services/ApiAiAssistant.ts +273 -0
  290. package/test/unit/spec/services/EntryPoint.ts +87 -40
  291. package/test/unit/spec/services/Queue.ts +123 -12
  292. package/test/unit/spec/services/UserPreference.ts +401 -0
  293. package/test/unit/spec/services/WebCallingService.ts +7 -1
  294. package/test/unit/spec/services/WebexCrossClientService.ts +261 -0
  295. package/test/unit/spec/services/WxAppTelephonyMercurySync.ts +113 -0
  296. package/test/unit/spec/services/config/Util.ts +85 -0
  297. package/test/unit/spec/services/config/index.ts +85 -29
  298. package/test/unit/spec/services/core/Utils.ts +481 -2
  299. package/test/unit/spec/services/core/WebexRequest.ts +3 -1
  300. package/test/unit/spec/services/core/aqm-reqs.ts +113 -1
  301. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +137 -41
  302. package/test/unit/spec/services/core/websocket/connection-service.ts +3 -1
  303. package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
  304. package/test/unit/spec/services/task/Task.ts +677 -0
  305. package/test/unit/spec/services/task/TaskFactory.ts +99 -0
  306. package/test/unit/spec/services/task/TaskManager.ts +2209 -918
  307. package/test/unit/spec/services/task/TaskUtils.ts +235 -0
  308. package/test/unit/spec/services/task/WebexCallingUtils.ts +153 -0
  309. package/test/unit/spec/services/task/contact.ts +33 -0
  310. package/test/unit/spec/services/task/dialer.ts +372 -96
  311. package/test/unit/spec/services/task/digital/Digital.ts +105 -0
  312. package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +3433 -0
  313. package/test/unit/spec/services/task/state-machine/guards.ts +839 -0
  314. package/test/unit/spec/services/task/state-machine/types.ts +18 -0
  315. package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +3101 -0
  316. package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
  317. package/test/unit/spec/services/task/voice/Voice.ts +1523 -0
  318. package/test/unit/spec/services/task/voice/WebRTC.ts +235 -0
  319. package/test/unit/spec/services/task/voice/wxAppVoiceMethods.ts +459 -0
  320. package/umd/contact-center.min.js +2 -2
  321. package/umd/contact-center.min.js.map +1 -1
  322. package/dist/services/task/index.js +0 -1525
  323. package/dist/services/task/index.js.map +0 -1
  324. package/src/services/task/index.ts +0 -1801
  325. package/test/unit/spec/services/task/index.ts +0 -2184
@@ -0,0 +1,860 @@
1
+ # Metrics — 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 | `metrics` |
10
+ | Source path(s) | `src/metrics` |
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
+ Metrics is one of nine confirmed Contact Center SDK modules. Own timing, taxonomy, queuing, payload preparation, and submission for Contact Center behavioral, operational, and business telemetry. Existing reviewed documentation is migrated by meaning and code/tests remain the behavioral referee.
27
+
28
+ - **Singleton Pattern**: Single `MetricsManager` instance shared across the entire SDK
29
+
30
+ - **Three Metric Types**: Behavioral (user actions), operational (system events), business (business-level analytics)
31
+
32
+ - **Event Timing**: `timeEvent` + `trackEvent` pattern automatically calculates `duration_ms`
33
+
34
+ - **Queued Submission**: Events are queued until the Webex SDK is ready, then submitted in order
35
+
36
+ - **Behavioral Taxonomy**: Structured `product.agent.target.verb` naming convention for behavioral events
37
+
38
+ - **Payload Preparation**: Automatic cleanup of empty fields, space-to-underscore conversion, and `tabHidden` metadata
39
+
40
+ - **AQM Response Helpers**: Static methods to extract common tracking fields from AQM responses
41
+
42
+ ## Purpose / Responsibility
43
+ Own timing, taxonomy, queuing, payload preparation, and submission for Contact Center behavioral, operational, and business telemetry.
44
+
45
+ ## Stack
46
+ TypeScript 5.4 singleton service, Webex internal metrics APIs, LoggerProxy, Jest 27.
47
+
48
+ ## Folder / Package Structure
49
+ ```text
50
+ src/metrics/
51
+ ├── MetricsManager.ts
52
+ ├── behavioral-events.ts
53
+ ├── constants.ts
54
+ ```
55
+
56
+ ```text
57
+ src/metrics/
58
+ ├── MetricsManager.ts # Singleton metrics manager
59
+ ├── behavioral-events.ts # Behavioral event taxonomy mapping
60
+ ├── constants.ts # METRIC_EVENT_NAMES constants
61
+ └── ai-docs/
62
+ ├── AGENTS.md # Usage documentation (see PR #4762)
63
+ └── ARCHITECTURE.md # Preserved legacy, noncanonical architecture guide
64
+ ```
65
+
66
+ ## Key Files (source of truth)
67
+ | File | Holds |
68
+ |---|---|
69
+ | `src/metrics/MetricsManager.ts` | Authoritative Metrics implementation or contract source. |
70
+ | `src/metrics/behavioral-events.ts` | Authoritative Metrics implementation or contract source. |
71
+ | `src/metrics/constants.ts` | Authoritative Metrics implementation or contract source. |
72
+
73
+ ## Public Surface
74
+ | Contract ID | Type | Surface | Purpose | Compatibility / deprecation | Schema / detail link | Root index |
75
+ |---|---|---|---|---|---|---|
76
+ | `metrics.surface` | SDK / event / internal API | Internal `MetricsManager` singleton, metric event constants, taxonomy lookup, timing, and tracking helpers. | Stable module consumption boundary. | Additive changes by default; breaking package exports require a major-version transition. | `src/metrics/MetricsManager.ts` | `../../../ai-docs/CONTRACTS.md` |
77
+
78
+ Compatibility notes:
79
+ - Do not remove or reinterpret exported symbols/events without a documented consumer migration.
80
+
81
+ Returns the singleton instance. On first call with `{webex}`, binds to the Webex SDK and begins listening for the `ready` event.
82
+
83
+ **Parameters**:
84
+
85
+ - `options` (object, optional): `{webex: WebexSDK}` - The Webex SDK instance
86
+
87
+ **Returns**: `MetricsManager`
88
+
89
+ **Example**:
90
+
91
+ ```typescript
92
+ // During initialization (called internally by cc.register())
93
+ const metrics = MetricsManager.getInstance({webex});
94
+
95
+ // Subsequent calls (no webex needed)
96
+ const metrics = MetricsManager.getInstance();
97
+ ```
98
+
99
+ Starts a timer for one or more event keys. When a matching `trackEvent` / `trackBehavioralEvent` / `trackOperationalEvent` / `trackBusinessEvent` is called, `duration_ms` is automatically added to the payload.
100
+
101
+ **Parameters**:
102
+
103
+ - `keys` (string | string[]): One or more `METRIC_EVENT_NAMES` values. The first key is the tracking key; all keys in the array will resolve the same timer.
104
+
105
+ **Returns**: `void`
106
+
107
+ **Example**:
108
+
109
+ ```typescript
110
+ // Single key
111
+ metrics.timeEvent(METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS);
112
+
113
+ // Multiple keys (success/failure share one timer)
114
+ metrics.timeEvent([
115
+ METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS,
116
+ METRIC_EVENT_NAMES.STATION_LOGIN_FAILED,
117
+ ]);
118
+ ```
119
+
120
+ Tracks an event across one or more metric services.
121
+
122
+ **Parameters**:
123
+
124
+ - `name` (METRIC_EVENT_NAMES): The event name constant
125
+
126
+ - `payload` (EventPayload, optional): Key-value pairs of event data
127
+
128
+ - `metricServices` (MetricsType[], optional): Array of `'behavioral'` | `'operational'` | `'business'` (default: `['behavioral']`)
129
+
130
+ **Returns**: `void`
131
+
132
+ **Example**:
133
+
134
+ ```typescript
135
+ // Behavioral only (default)
136
+ metrics.trackEvent(METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS, {agentId: '123'});
137
+
138
+ // Multiple services
139
+ metrics.trackEvent(
140
+ METRIC_EVENT_NAMES.TASK_ACCEPT_SUCCESS,
141
+ {interactionId: 'abc'},
142
+ ['behavioral', 'operational']
143
+ );
144
+ ```
145
+
146
+ Tracks a single behavioral event. Looks up the event taxonomy from `behavioral-events.ts` and submits via `webex.internal.newMetrics.submitBehavioralEvent`.
147
+
148
+ **Parameters**:
149
+
150
+ - `name` (METRIC_EVENT_NAMES): The event name
151
+
152
+ - `options` (EventPayload, optional): Additional payload data
153
+
154
+ **Returns**: `void`
155
+
156
+ Tracks a single operational event. Prefixes the event name with `WXCC_SDK_` and submits via `webex.internal.newMetrics.submitOperationalEvent`.
157
+
158
+ **Parameters**:
159
+
160
+ - `name` (METRIC_EVENT_NAMES): The event name
161
+
162
+ - `options` (EventPayload, optional): Additional payload data
163
+
164
+ **Returns**: `void`
165
+
166
+ Tracks a single business event. Prefixes the event name with `WXCC_SDK_` and submits via `webex.internal.newMetrics.submitBusinessEvent` with `appType: 'wxcc_sdk'`.
167
+
168
+ **Parameters**:
169
+
170
+ - `name` (METRIC_EVENT_NAMES): The event name
171
+
172
+ - `options` (EventPayload, optional): Additional payload data
173
+
174
+ **Returns**: `void`
175
+
176
+ Enables or disables metrics collection. When disabled, all pending events are cleared and new events are dropped.
177
+
178
+ **Parameters**:
179
+
180
+ - `disabled` (boolean): `true` to disable, `false` to enable
181
+
182
+ **Returns**: `void`
183
+
184
+ Static helper that extracts common tracking fields from an AQM success response.
185
+
186
+ **Parameters**:
187
+
188
+ - `response` (any): The AQM response object
189
+
190
+ **Returns**: `Record<string, any>` with fields: `agentId`, `agentSessionId`, `teamId`, `siteId`, `orgId`, `eventType`, `trackingId`, `notifTrackingId`
191
+
192
+ **Example**:
193
+
194
+ ```typescript
195
+ const fields = MetricsManager.getCommonTrackingFieldForAQMResponse(aqmResponse);
196
+ metrics.trackEvent(METRIC_EVENT_NAMES.TASK_ACCEPT_SUCCESS, {
197
+ ...fields,
198
+ interactionId: task.interactionId,
199
+ });
200
+ ```
201
+
202
+ Resets the singleton instance. Used for testing only.
203
+
204
+ **Returns**: `void`
205
+
206
+ All event names are defined in `METRIC_EVENT_NAMES` (`constants.ts`). Events follow a `<Category> <Action> <Result>` pattern.
207
+
208
+ | Constant | Value | Description |
209
+ |---|---|---|
210
+ | `STATION_LOGIN_SUCCESS` | `'Station Login Success'` | Agent station login succeeded |
211
+ | `STATION_LOGIN_FAILED` | `'Station Login Failed'` | Agent station login failed |
212
+ | `STATION_LOGOUT_SUCCESS` | `'Station Logout Success'` | Agent station logout succeeded |
213
+ | `STATION_LOGOUT_FAILED` | `'Station Logout Failed'` | Agent station logout failed |
214
+ | `STATION_RELOGIN_SUCCESS` | `'Station Relogin Success'` | Silent relogin succeeded |
215
+ | `STATION_RELOGIN_FAILED` | `'Station Relogin Failed'` | Silent relogin failed |
216
+ | `AGENT_STATE_CHANGE_SUCCESS` | `'Agent State Change Success'` | State change succeeded |
217
+ | `AGENT_STATE_CHANGE_FAILED` | `'Agent State Change Failed'` | State change failed |
218
+ | `FETCH_BUDDY_AGENTS_SUCCESS` | `'Fetch Buddy Agents Success'` | Buddy agents fetch succeeded |
219
+ | `FETCH_BUDDY_AGENTS_FAILED` | `'Fetch Buddy Agents Failed'` | Buddy agents fetch failed |
220
+ | `AGENT_RONA` | `'Agent RONA'` | Agent Ring-On-No-Answer triggered |
221
+ | `AGENT_CONTACT_ASSIGN_FAILED` | `'Agent Contact Assign Failed'` | Contact assignment failed |
222
+ | `AGENT_INVITE_FAILED` | `'Agent Invite Failed'` | Agent invite failed |
223
+ | `AGENT_DEVICE_TYPE_UPDATE_SUCCESS` | `'Agent Device Type Update Success'` | Device type update succeeded |
224
+ | `AGENT_DEVICE_TYPE_UPDATE_FAILED` | `'Agent Device Type Update Failed'` | Device type update failed |
225
+ | `TASK_ACCEPT_SUCCESS` / `FAILED` | `'Task Accept ...'` | Task accept result |
226
+ | `TASK_DECLINE_SUCCESS` / `FAILED` | `'Task Decline ...'` | Task decline result |
227
+ | `TASK_END_SUCCESS` / `FAILED` | `'Task End ...'` | Task end result |
228
+ | `TASK_WRAPUP_SUCCESS` / `FAILED` | `'Task Wrapup ...'` | Task wrapup result |
229
+ | `TASK_HOLD_SUCCESS` / `FAILED` | `'Task Hold ...'` | Task hold result |
230
+ | `TASK_RESUME_SUCCESS` / `FAILED` | `'Task Resume ...'` | Task resume result |
231
+ | `TASK_CONSULT_START_SUCCESS` / `FAILED` | `'Task Consult Start ...'` | Consult start result |
232
+ | `TASK_CONSULT_END_SUCCESS` / `FAILED` | `'Task Consult End ...'` | Consult end result |
233
+ | `TASK_TRANSFER_SUCCESS` / `FAILED` | `'Task Transfer ...'` | Transfer result |
234
+ | `TASK_PAUSE_RECORDING_SUCCESS` / `FAILED` | `'Task Pause Recording ...'` | Pause recording result |
235
+ | `TASK_RESUME_RECORDING_SUCCESS` / `FAILED` | `'Task Resume Recording ...'` | Resume recording result |
236
+ | `TASK_ACCEPT_CONSULT_SUCCESS` / `FAILED` | `'Task Accept Consult ...'` | Accept consult result |
237
+ | `TASK_AUTO_ANSWER_SUCCESS` / `FAILED` | `'Task Auto Answer ...'` | Auto-answer result |
238
+ | `TASK_OUTDIAL_SUCCESS` / `FAILED` | `'Task Outdial ...'` | Outdial result |
239
+ | `TASK_CONFERENCE_START_SUCCESS` / `FAILED` | `'Task Conference Start ...'` | Conference start result |
240
+ | `TASK_CONFERENCE_END_SUCCESS` / `FAILED` | `'Task Conference End ...'` | Conference end result |
241
+ | `TASK_CONFERENCE_TRANSFER_SUCCESS` / `FAILED` | `'Task Conference Transfer ...'` | Conference transfer result |
242
+ | `TASK_CONFERENCE_EXIT_SUCCESS` / `FAILED` | `'Task Conference Exit ...'` | Conference exit result |
243
+ | `TASK_CONFERENCE_PARTICIPANT_DROP_SUCCESS` / `FAILED` | `'Task Conference Participant Drop ...'` | Participant Drop result |
244
+ | `TASK_SWITCH_CALL_SUCCESS` / `FAILED` | `'Task Switch Call ...'` | Switch call result |
245
+ | `WEBSOCKET_REGISTER_SUCCESS` / `FAILED` | `'Websocket Register ...'` | WebSocket registration result |
246
+ | `WEBSOCKET_DEREGISTER_SUCCESS` / `FAIL` | `'Websocket Deregister ...'` | WebSocket deregistration result |
247
+ | `WEBSOCKET_EVENT_RECEIVED` | `'Websocket Event Received'` | WebSocket event received |
248
+ | `UPLOAD_LOGS_SUCCESS` / `FAILED` | `'Upload Logs ...'` | Log upload result |
249
+ | `ENTRYPOINT_FETCH_SUCCESS` / `FAILED` | `'Entrypoint Fetch ...'` | Entry point fetch result |
250
+ | `ADDRESSBOOK_FETCH_SUCCESS` / `FAILED` | `'AddressBook Fetch ...'` | Address book fetch result |
251
+ | `QUEUE_FETCH_SUCCESS` / `FAILED` | `'Queue Fetch ...'` | Queue fetch result |
252
+ | `OUTDIAL_ANI_EP_FETCH_SUCCESS` / `FAILED` | `'Outdial ANI Entries Fetch ...'` | Outdial ANI entries fetch result |
253
+
254
+ All event names are defined in `constants.ts` as `METRIC_EVENT_NAMES`. Events follow a `{Domain} {Action} {Success|Failed}` naming convention:
255
+
256
+ | Category | Success Event | Failure Event |
257
+ |---|---|---|
258
+ | Station Login | `STATION_LOGIN_SUCCESS` | `STATION_LOGIN_FAILED` |
259
+ | Station Logout | `STATION_LOGOUT_SUCCESS` | `STATION_LOGOUT_FAILED` |
260
+ | Station Relogin | `STATION_RELOGIN_SUCCESS` | `STATION_RELOGIN_FAILED` |
261
+ | State Change | `AGENT_STATE_CHANGE_SUCCESS` | `AGENT_STATE_CHANGE_FAILED` |
262
+ | Buddy Agents | `FETCH_BUDDY_AGENTS_SUCCESS` | `FETCH_BUDDY_AGENTS_FAILED` |
263
+ | WebSocket Register | `WEBSOCKET_REGISTER_SUCCESS` | `WEBSOCKET_REGISTER_FAILED` |
264
+ | Task Accept | `TASK_ACCEPT_SUCCESS` | `TASK_ACCEPT_FAILED` |
265
+ | Task Decline | `TASK_DECLINE_SUCCESS` | `TASK_DECLINE_FAILED` |
266
+ | Task End | `TASK_END_SUCCESS` | `TASK_END_FAILED` |
267
+ | Task Wrapup | `TASK_WRAPUP_SUCCESS` | `TASK_WRAPUP_FAILED` |
268
+ | Task Hold | `TASK_HOLD_SUCCESS` | `TASK_HOLD_FAILED` |
269
+ | Task Resume | `TASK_RESUME_SUCCESS` | `TASK_RESUME_FAILED` |
270
+ | Task Consult Start | `TASK_CONSULT_START_SUCCESS` | `TASK_CONSULT_START_FAILED` |
271
+ | Task Consult End | `TASK_CONSULT_END_SUCCESS` | `TASK_CONSULT_END_FAILED` |
272
+ | Task Transfer | `TASK_TRANSFER_SUCCESS` | `TASK_TRANSFER_FAILED` |
273
+ | Task Resume Recording | `TASK_RESUME_RECORDING_SUCCESS` | `TASK_RESUME_RECORDING_FAILED` |
274
+ | Task Pause Recording | `TASK_PAUSE_RECORDING_SUCCESS` | `TASK_PAUSE_RECORDING_FAILED` |
275
+ | Task Accept Consult | `TASK_ACCEPT_CONSULT_SUCCESS` | `TASK_ACCEPT_CONSULT_FAILED` |
276
+ | Task Auto Answer | `TASK_AUTO_ANSWER_SUCCESS` | `TASK_AUTO_ANSWER_FAILED` |
277
+ | Conference Start | `TASK_CONFERENCE_START_SUCCESS` | `TASK_CONFERENCE_START_FAILED` |
278
+ | Conference End | `TASK_CONFERENCE_END_SUCCESS` | `TASK_CONFERENCE_END_FAILED` |
279
+ | Conference Transfer | `TASK_CONFERENCE_TRANSFER_SUCCESS` | `TASK_CONFERENCE_TRANSFER_FAILED` |
280
+ | Conference Exit | `TASK_CONFERENCE_EXIT_SUCCESS` | `TASK_CONFERENCE_EXIT_FAILED` |
281
+ | Conference Participant Drop | `TASK_CONFERENCE_PARTICIPANT_DROP_SUCCESS` | `TASK_CONFERENCE_PARTICIPANT_DROP_FAILED` |
282
+ | Switch Call | `TASK_SWITCH_CALL_SUCCESS` | `TASK_SWITCH_CALL_FAILED` |
283
+ | Outdial | `TASK_OUTDIAL_SUCCESS` | `TASK_OUTDIAL_FAILED` |
284
+ | Upload Logs | `UPLOAD_LOGS_SUCCESS` | `UPLOAD_LOGS_FAILED` |
285
+ | WebSocket Deregister | `WEBSOCKET_DEREGISTER_SUCCESS` | `WEBSOCKET_DEREGISTER_FAIL` |
286
+ | Device Type Update | `AGENT_DEVICE_TYPE_UPDATE_SUCCESS` | `AGENT_DEVICE_TYPE_UPDATE_FAILED` |
287
+ | EntryPoint | `ENTRYPOINT_FETCH_SUCCESS` | `ENTRYPOINT_FETCH_FAILED` |
288
+ | AddressBook | `ADDRESSBOOK_FETCH_SUCCESS` | `ADDRESSBOOK_FETCH_FAILED` |
289
+ | Queue | `QUEUE_FETCH_SUCCESS` | `QUEUE_FETCH_FAILED` |
290
+ | Outdial ANI Entries | `OUTDIAL_ANI_EP_FETCH_SUCCESS` | `OUTDIAL_ANI_EP_FETCH_FAILED` |
291
+
292
+ Special events (no success/failure pair):
293
+
294
+ - `AGENT_RONA` — has behavioral taxonomy (`service.agent_rona.set`)
295
+
296
+ - `AGENT_CONTACT_ASSIGN_FAILED` — has behavioral taxonomy (`service.agent_contact_assign.fail`)
297
+
298
+ - `AGENT_INVITE_FAILED` — has behavioral taxonomy (`service.agent_invite.fail`)
299
+
300
+ - `WEBSOCKET_EVENT_RECEIVED` — **no** behavioral taxonomy (not in `eventTaxonomyMap`)
301
+
302
+ Of the 82 defined metric names, 73 have behavioral taxonomy and 9 do not. Events **without** an `eventTaxonomyMap` entry are the six `AI_ASSISTANT_*` names plus `WEBSOCKET_DEREGISTER_SUCCESS`, `WEBSOCKET_DEREGISTER_FAIL`, and `WEBSOCKET_EVENT_RECEIVED`.
303
+
304
+ ### Complete METRIC_EVENT_NAMES catalog
305
+
306
+ This table contains all 82 names from `src/metrics/constants.ts`; taxonomy presence is checked against `src/metrics/behavioral-events.ts`: 73 mapped and 9 unmapped.
307
+
308
+ | Constant | Emitted name | Behavioral taxonomy? |
309
+ |---|---|---|
310
+ | `STATION_LOGIN_SUCCESS` | `Station Login Success` | yes |
311
+ | `STATION_LOGIN_FAILED` | `Station Login Failed` | yes |
312
+ | `STATION_LOGOUT_SUCCESS` | `Station Logout Success` | yes |
313
+ | `STATION_LOGOUT_FAILED` | `Station Logout Failed` | yes |
314
+ | `STATION_RELOGIN_SUCCESS` | `Station Relogin Success` | yes |
315
+ | `STATION_RELOGIN_FAILED` | `Station Relogin Failed` | yes |
316
+ | `AGENT_STATE_CHANGE_SUCCESS` | `Agent State Change Success` | yes |
317
+ | `AGENT_STATE_CHANGE_FAILED` | `Agent State Change Failed` | yes |
318
+ | `FETCH_BUDDY_AGENTS_SUCCESS` | `Fetch Buddy Agents Success` | yes |
319
+ | `FETCH_BUDDY_AGENTS_FAILED` | `Fetch Buddy Agents Failed` | yes |
320
+ | `WEBSOCKET_REGISTER_SUCCESS` | `Websocket Register Success` | yes |
321
+ | `WEBSOCKET_REGISTER_FAILED` | `Websocket Register Failed` | yes |
322
+ | `AGENT_RONA` | `Agent RONA` | yes |
323
+ | `AGENT_CONTACT_ASSIGN_FAILED` | `Agent Contact Assign Failed` | yes |
324
+ | `AGENT_INVITE_FAILED` | `Agent Invite Failed` | yes |
325
+ | `TASK_ACCEPT_SUCCESS` | `Task Accept Success` | yes |
326
+ | `TASK_ACCEPT_FAILED` | `Task Accept Failed` | yes |
327
+ | `TASK_DECLINE_SUCCESS` | `Task Decline Success` | yes |
328
+ | `TASK_DECLINE_FAILED` | `Task Decline Failed` | yes |
329
+ | `TASK_END_SUCCESS` | `Task End Success` | yes |
330
+ | `TASK_END_FAILED` | `Task End Failed` | yes |
331
+ | `TASK_WRAPUP_SUCCESS` | `Task Wrapup Success` | yes |
332
+ | `TASK_WRAPUP_FAILED` | `Task Wrapup Failed` | yes |
333
+ | `TASK_HOLD_SUCCESS` | `Task Hold Success` | yes |
334
+ | `TASK_HOLD_FAILED` | `Task Hold Failed` | yes |
335
+ | `TASK_RESUME_SUCCESS` | `Task Resume Success` | yes |
336
+ | `TASK_RESUME_FAILED` | `Task Resume Failed` | yes |
337
+ | `TASK_CONSULT_START_SUCCESS` | `Task Consult Start Success` | yes |
338
+ | `TASK_CONSULT_START_FAILED` | `Task Consult Start Failed` | yes |
339
+ | `TASK_CONSULT_END_SUCCESS` | `Task Consult End Success` | yes |
340
+ | `TASK_CONSULT_END_FAILED` | `Task Consult End Failed` | yes |
341
+ | `TASK_TRANSFER_SUCCESS` | `Task Transfer Success` | yes |
342
+ | `TASK_TRANSFER_FAILED` | `Task Transfer Failed` | yes |
343
+ | `TASK_RESUME_RECORDING_SUCCESS` | `Task Resume Recording Success` | yes |
344
+ | `TASK_RESUME_RECORDING_FAILED` | `Task Resume Recording Failed` | yes |
345
+ | `TASK_PAUSE_RECORDING_SUCCESS` | `Task Pause Recording Success` | yes |
346
+ | `TASK_PAUSE_RECORDING_FAILED` | `Task Pause Recording Failed` | yes |
347
+ | `TASK_ACCEPT_CONSULT_SUCCESS` | `Task Accept Consult Success` | yes |
348
+ | `TASK_ACCEPT_CONSULT_FAILED` | `Task Accept Consult Failed` | yes |
349
+ | `TASK_AUTO_ANSWER_SUCCESS` | `Task Auto Answer Success` | yes |
350
+ | `TASK_AUTO_ANSWER_FAILED` | `Task Auto Answer Failed` | yes |
351
+ | `TASK_CONFERENCE_START_SUCCESS` | `Task Conference Start Success` | yes |
352
+ | `TASK_CONFERENCE_START_FAILED` | `Task Conference Start Failed` | yes |
353
+ | `TASK_CONFERENCE_END_SUCCESS` | `Task Conference End Success` | yes |
354
+ | `TASK_CONFERENCE_END_FAILED` | `Task Conference End Failed` | yes |
355
+ | `TASK_CONFERENCE_TRANSFER_SUCCESS` | `Task Conference Transfer Success` | yes |
356
+ | `TASK_CONFERENCE_TRANSFER_FAILED` | `Task Conference Transfer Failed` | yes |
357
+ | `TASK_CONFERENCE_EXIT_SUCCESS` | `Task Conference Exit Success` | yes |
358
+ | `TASK_CONFERENCE_EXIT_FAILED` | `Task Conference Exit Failed` | yes |
359
+ | `TASK_CONFERENCE_PARTICIPANT_DROP_SUCCESS` | `Task Conference Participant Drop Success` | yes |
360
+ | `TASK_CONFERENCE_PARTICIPANT_DROP_FAILED` | `Task Conference Participant Drop Failed` | yes |
361
+ | `TASK_SWITCH_CALL_SUCCESS` | `Task Switch Call Success` | yes |
362
+ | `TASK_SWITCH_CALL_FAILED` | `Task Switch Call Failed` | yes |
363
+ | `TASK_OUTDIAL_SUCCESS` | `Task Outdial Success` | yes |
364
+ | `TASK_OUTDIAL_FAILED` | `Task Outdial Failed` | yes |
365
+ | `UPLOAD_LOGS_SUCCESS` | `Upload Logs Success` | yes |
366
+ | `UPLOAD_LOGS_FAILED` | `Upload Logs Failed` | yes |
367
+ | `WEBSOCKET_DEREGISTER_SUCCESS` | `Websocket Deregister Success` | no |
368
+ | `WEBSOCKET_DEREGISTER_FAIL` | `Websocket Deregister Failed` | no |
369
+ | `AGENT_DEVICE_TYPE_UPDATE_SUCCESS` | `Agent Device Type Update Success` | yes |
370
+ | `AGENT_DEVICE_TYPE_UPDATE_FAILED` | `Agent Device Type Update Failed` | yes |
371
+ | `WEBSOCKET_EVENT_RECEIVED` | `Websocket Event Received` | no |
372
+ | `ENTRYPOINT_FETCH_SUCCESS` | `Entrypoint Fetch Success` | yes |
373
+ | `ENTRYPOINT_FETCH_FAILED` | `Entrypoint Fetch Failed` | yes |
374
+ | `ADDRESSBOOK_FETCH_SUCCESS` | `AddressBook Fetch Success` | yes |
375
+ | `ADDRESSBOOK_FETCH_FAILED` | `AddressBook Fetch Failed` | yes |
376
+ | `QUEUE_FETCH_SUCCESS` | `Queue Fetch Success` | yes |
377
+ | `QUEUE_FETCH_FAILED` | `Queue Fetch Failed` | yes |
378
+ | `OUTDIAL_ANI_EP_FETCH_SUCCESS` | `Outdial ANI Entries Fetch Success` | yes |
379
+ | `OUTDIAL_ANI_EP_FETCH_FAILED` | `Outdial ANI Entries Fetch Failed` | yes |
380
+ | `CAMPAIGN_PREVIEW_ACCEPT_SUCCESS` | `Campaign Preview Accept Success` | yes |
381
+ | `CAMPAIGN_PREVIEW_ACCEPT_FAILED` | `Campaign Preview Accept Failed` | yes |
382
+ | `CAMPAIGN_PREVIEW_SKIP_SUCCESS` | `Campaign Preview Skip Success` | yes |
383
+ | `CAMPAIGN_PREVIEW_SKIP_FAILED` | `Campaign Preview Skip Failed` | yes |
384
+ | `CAMPAIGN_PREVIEW_REMOVE_SUCCESS` | `Campaign Preview Remove Success` | yes |
385
+ | `CAMPAIGN_PREVIEW_REMOVE_FAILED` | `Campaign Preview Remove Failed` | yes |
386
+ | `AI_ASSISTANT_SEND_EVENT_SUCCESS` | `AI Assistant Send Event Success` | no |
387
+ | `AI_ASSISTANT_SEND_EVENT_FAILED` | `AI Assistant Send Event Failed` | no |
388
+ | `AI_ASSISTANT_GET_SUGGESTED_RESPONSE_SUCCESS` | `AI Assistant Get Suggested Response Success` | no |
389
+ | `AI_ASSISTANT_GET_SUGGESTED_RESPONSE_FAILED` | `AI Assistant Get Suggested Response Failed` | no |
390
+ | `AI_ASSISTANT_FETCH_HISTORIC_TRANSCRIPTS_SUCCESS` | `AI Assistant Fetch Historic Transcripts Success` | no |
391
+ | `AI_ASSISTANT_FETCH_HISTORIC_TRANSCRIPTS_FAILED` | `AI Assistant Fetch Historic Transcripts Failed` | no |
392
+
393
+ Defined names without an `eventTaxonomyMap` entry: `AI_ASSISTANT_FETCH_HISTORIC_TRANSCRIPTS_FAILED`, `AI_ASSISTANT_FETCH_HISTORIC_TRANSCRIPTS_SUCCESS`, `AI_ASSISTANT_GET_SUGGESTED_RESPONSE_FAILED`, `AI_ASSISTANT_GET_SUGGESTED_RESPONSE_SUCCESS`, `AI_ASSISTANT_SEND_EVENT_FAILED`, `AI_ASSISTANT_SEND_EVENT_SUCCESS`, `WEBSOCKET_DEREGISTER_FAIL`, `WEBSOCKET_DEREGISTER_SUCCESS`, `WEBSOCKET_EVENT_RECEIVED`.
394
+
395
+ ## Requires (dependencies)
396
+ - `webex.internal.newMetrics` submission APIs
397
+ - Webex ready lifecycle
398
+ - LoggerProxy and browser visibility metadata
399
+
400
+ - **`@webex/internal-plugin-metrics`**: Provides `webex.internal.newMetrics` for actual metric submission (`submitBehavioralEvent`, `submitOperationalEvent`, `submitBusinessEvent`)
401
+
402
+ - **`LoggerProxy`**: Used for error logging within the metrics module
403
+
404
+ - **`Failure` type** (from `services/core/GlobalTypes`): Used in `getCommonTrackingFieldForAQMResponseFailed`
405
+
406
+ - **`PRODUCT_NAME`** (from `constants.ts`): Set to `'wxcc_sdk'`, used as the product identifier in behavioral taxonomy and as prefix for operational/business event names
407
+
408
+ ## Requirements
409
+ | ID | WHAT | WHY | Source Evidence | Test / Example Evidence | Assumptions / Gaps | Confidence |
410
+ |---|---|---|---|---|---|---|
411
+ | METRICS-R-001 | Track only names defined by METRIC_EVENT_NAMES and keep the canonical catalog synchronized with the const object. | Telemetry queries and dashboards depend on exact stable event names. | `src/metrics/constants.ts` | `test/unit/spec/metrics/MetricsManager.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
412
+ | METRICS-R-002 | Map behavioral events through eventTaxonomyMap and explicitly identify defined names without taxonomy. | Undefined taxonomy must not be mistaken for an emitted or classified behavioral event. | `src/metrics/behavioral-events.ts` | `test/unit/spec/metrics/behavioral-events.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
413
+ | METRICS-R-003 | When metrics are disabled, clear pending events and make `timeEvent` plus all tracking methods return without recording/submitting. | Telemetry must never block or alter product behavior and disablement must be comprehensive. | `src/metrics/MetricsManager.ts` | `test/unit/spec/metrics/MetricsManager.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
414
+ | METRICS-R-004 | Queue submissions until the host SDK is ready and flush through the correct behavioral/operational/business service. | Early lifecycle telemetry must not be lost solely because the host is not ready. | `src/metrics/MetricsManager.ts` | `test/unit/spec/metrics/MetricsManager.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
415
+ | METRICS-R-005 | Submit through the host SDK's `webex.internal.newMetrics` client without storing credentials or implementing authorization policy in MetricsManager. | Host-owned authentication keeps telemetry credential handling outside the Contact Center metrics module. | `src/metrics/MetricsManager.ts` | `test/unit/spec/metrics/MetricsManager.ts` | None; authentication is inherited and credential ownership is explicitly N/A. | PRESENT |
416
+
417
+ ## Design Overview
418
+ Metrics separates its stable consumption boundary from collaborators so ownership and failure behavior stay explicit. Telemetry is deliberately non-blocking and queue-backed so product behavior never waits for metrics; failures are logged rather than propagated.
419
+
420
+ > **Purpose**: Track behavioral, operational, and business metrics for Contact Center SDK operations using a singleton `MetricsManager`. Provides event timing, payload preparation, batching, and submission to the Webex metrics backend.
421
+
422
+ Each behavioral event maps to a structured taxonomy in `behavioral-events.ts`:
423
+
424
+ ```text
425
+ {product}.{agent}.{target}.{verb}
426
+ ```
427
+
428
+ - **product**: Always `'wxcc_sdk'` (from `PRODUCT_NAME`)
429
+
430
+ - **agent**: `'user'` for user-initiated actions, `'service'` for system-generated events
431
+
432
+ - **target**: Snake_case description of the action (e.g., `'station_login'`, `'task_accept'`)
433
+
434
+ - **verb**: `'complete'` for success, `'fail'` for failure, `'set'` for RONA events
435
+
436
+ **Example**: `STATION_LOGIN_SUCCESS` maps to `wxcc_sdk.user.station_login.complete`
437
+
438
+ > **Note**: The following events do **not** have behavioral taxonomy mappings in `behavioral-events.ts`:
439
+ > - `AI_ASSISTANT_SEND_EVENT_SUCCESS`
440
+ > - `AI_ASSISTANT_SEND_EVENT_FAILED`
441
+ > - `AI_ASSISTANT_GET_SUGGESTED_RESPONSE_SUCCESS`
442
+ > - `AI_ASSISTANT_GET_SUGGESTED_RESPONSE_FAILED`
443
+ > - `AI_ASSISTANT_FETCH_HISTORIC_TRANSCRIPTS_SUCCESS`
444
+ > - `AI_ASSISTANT_FETCH_HISTORIC_TRANSCRIPTS_FAILED`
445
+ > - `WEBSOCKET_DEREGISTER_SUCCESS`
446
+ > - `WEBSOCKET_DEREGISTER_FAIL`
447
+ > - `WEBSOCKET_EVENT_RECEIVED`
448
+ >
449
+ > Calling `trackBehavioralEvent` with these event names will push an event with an `undefined` taxonomy.
450
+
451
+ > **Purpose**: Technical documentation for the metrics collection, batching, and submission system within the Contact Center SDK.
452
+
453
+ Each metric event name maps to a `BehavioralEventTaxonomy` with four fields:
454
+
455
+ ```typescript
456
+ type BehavioralEventTaxonomy = {
457
+ product: MetricEventProduct; // Always PRODUCT_NAME ('wxcc_sdk')
458
+ agent: MetricEventAgent; // 'user' or 'service'
459
+ target: string; // e.g., 'station_login', 'task_accept'
460
+ verb: MetricEventVerb; // 'complete' for success, 'fail' for failure
461
+ };
462
+ ```
463
+
464
+ The final behavioral event name is constructed as: `{product}.{agent}.{target}.{verb}`
465
+
466
+ Example: `wxcc_sdk.user.station_login.complete`
467
+
468
+ The mapping is defined in `behavioral-events.ts` via `eventTaxonomyMap` and accessed through `getEventTaxonomy(name)`.
469
+
470
+ Participant Drop uses target `task_conference_participant_drop` with `complete` for success and `fail` for failure. Its metric payload is limited to task/request correlation and standard AQM tracking fields; participant IDs, numbers, names, URLs, headers, and raw routing payloads are excluded.
471
+
472
+ ```mermaid
473
+ flowchart LR
474
+ A[timeEvent keys] --> B[runningEvents stores startTime + key Set]
475
+ B --> C[trackEvent called with one of the keys]
476
+ C --> D[addDurationIfTimed matches key]
477
+ D --> E[Calculates duration_ms = now - startTime]
478
+ E --> F[Removes all keys for that operation]
479
+ F --> G[Attaches duration_ms to payload]
480
+ ```
481
+
482
+ Usage pattern from `cc.ts`:
483
+
484
+ ```typescript
485
+ // Before operation
486
+ this.metricsManager.timeEvent([
487
+ METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS,
488
+ METRIC_EVENT_NAMES.STATION_LOGIN_FAILED,
489
+ ]);
490
+
491
+ // On success
492
+ this.metricsManager.trackEvent(
493
+ METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS,
494
+ { ...MetricsManager.getCommonTrackingFieldForAQMResponse(resp) },
495
+ ['behavioral', 'operational', 'business']
496
+ );
497
+
498
+ // On failure
499
+ this.metricsManager.trackEvent(
500
+ METRIC_EVENT_NAMES.STATION_LOGIN_FAILED,
501
+ { ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(failure) },
502
+ ['behavioral', 'operational', 'business']
503
+ );
504
+ ```
505
+
506
+ Two static helpers extract standardized fields from AQM responses for metric payloads:
507
+
508
+ Extracts: `agentId`, `agentSessionId`, `teamId`, `siteId`, `orgId`, `eventType`, `trackingId`, `notifTrackingId`
509
+
510
+ ## Data Flow
511
+ ```mermaid
512
+ flowchart TD
513
+ A[cc.ts calls metricsManager.timeEvent] --> B[Store startTime + keys in runningEvents]
514
+ B --> C[Operation executes]
515
+ C --> D{Success or Failure?}
516
+ D -->|Success| E[cc.ts calls metricsManager.trackEvent with success name]
517
+ D -->|Failure| F[cc.ts calls metricsManager.trackEvent with failure name]
518
+ E --> G[addDurationIfTimed attaches duration_ms]
519
+ F --> G
520
+ G --> H[preparePayload cleans and enriches]
521
+ H --> I{Metric type?}
522
+ I -->|behavioral| J[Push to pendingBehavioralEvents]
523
+ I -->|operational| K[Push to pendingOperationalEvents]
524
+ I -->|business| L[Push to pendingBusinessEvents]
525
+ J --> M[submitPendingBehavioralEvents]
526
+ K --> N[submitPendingOperationalEvents]
527
+ L --> O[submitPendingBusinessEvents]
528
+ M --> P[webex.internal.newMetrics.submitBehavioralEvent]
529
+ N --> Q[webex.internal.newMetrics.submitOperationalEvent]
530
+ O --> R[webex.internal.newMetrics.submitBusinessEvent]
531
+ ```
532
+
533
+ ## Sequence Diagram(s)
534
+ Sequence coverage:
535
+
536
+ | Operation group | Diagram | Failure / recovery coverage |
537
+ |---|---|---|
538
+ | Time and track an event | Timing and tracking | Success/failure keys share one timer; missing timing data leaves the payload untimed. |
539
+ | Queue until SDK readiness | SDK readiness | A not-ready SDK retains events; READY drains them through the configured metrics service. |
540
+ | Submit behavioral/operational/business events | Category submission | The module does not retry or requeue after handing an event to `newMetrics`. |
541
+ | Disable metrics | Disablement | Pending queues are cleared and future timing/tracking calls return immediately. |
542
+
543
+ ### Timing and tracking
544
+
545
+ ```mermaid
546
+ sequenceDiagram
547
+ participant CC as ContactCenter (cc.ts)
548
+ participant MM as MetricsManager
549
+ participant NM as webex.internal.newMetrics
550
+
551
+ CC->>MM: timeEvent([SUCCESS_KEY, FAILURE_KEY])
552
+ Note over MM: Store startTime + key set in runningEvents
553
+ CC->>CC: Execute operation (e.g., stationLogin)
554
+ Note over MM: trackEvent defaults to ['behavioral'] only if no metricServices specified
555
+ alt Success
556
+ CC->>MM: trackEvent(SUCCESS_KEY, payload, ['behavioral', 'operational', 'business'])
557
+ else Failure
558
+ CC->>MM: trackEvent(FAILURE_KEY, payload, ['behavioral', 'operational', 'business'])
559
+ end
560
+ MM->>MM: addDurationIfTimed → attach duration_ms
561
+ MM->>MM: preparePayload → clean empty fields, add tabHidden
562
+ loop For each metric type
563
+ MM->>MM: Push to pending queue
564
+ alt readyToSubmitEvents
565
+ MM->>NM: submit[Behavioral|Operational|Business]Event
566
+ else not ready
567
+ Note over MM: Events stay queued until SDK ready
568
+ end
569
+ end
570
+ ```
571
+
572
+ ### SDK readiness
573
+
574
+ ```mermaid
575
+ sequenceDiagram
576
+ participant CC as ContactCenter
577
+ participant MM as MetricsManager
578
+ participant Webex as WebexSDK
579
+
580
+ CC->>MM: getInstance({webex})
581
+ MM->>MM: Create singleton (if needed)
582
+ MM->>MM: setWebex(webex)
583
+ opt webex.ready === true
584
+ MM->>MM: setReadyToSubmitEvents()
585
+ MM->>MM: submitPendingEvents()
586
+ end
587
+ MM->>Webex: webex.once('ready', callback)
588
+ Note over MM: 'ready' listener is always registered
589
+ Webex-->>MM: 'ready' event fires
590
+ MM->>MM: setReadyToSubmitEvents()
591
+ MM->>MM: submitPendingEvents()
592
+ ```
593
+
594
+ ### Category submission
595
+
596
+ ```mermaid
597
+ sequenceDiagram
598
+ participant Caller
599
+ participant MM as MetricsManager
600
+ participant NM as webex.internal.newMetrics
601
+ Caller->>MM: trackEvent(name, payload, metricServices)
602
+ loop each requested metric service
603
+ alt behavioral
604
+ MM->>NM: submitBehavioralEvent(taxonomy + payload)
605
+ else operational
606
+ MM->>NM: submitOperationalEvent(WXCC_SDK_* + payload)
607
+ else business
608
+ MM->>NM: submitBusinessEvent(WXCC_SDK_* + appType)
609
+ else invalid metric service
610
+ MM->>MM: LoggerProxy.error(invalid type)
611
+ end
612
+ end
613
+ Note over MM,NM: No module-level retry or requeue after submission handoff
614
+ ```
615
+
616
+ ### Disablement
617
+
618
+ ```mermaid
619
+ sequenceDiagram
620
+ participant Caller
621
+ participant MM as MetricsManager
622
+ Caller->>MM: setMetricsDisabled(true)
623
+ MM->>MM: clear pending behavioral/operational/business queues
624
+ Caller->>MM: timeEvent(...) / trackEvent(...)
625
+ alt metricsDisabled
626
+ MM-->>Caller: return without timing, queueing, or submission
627
+ else re-enabled
628
+ MM->>MM: use normal timing/queue flow
629
+ end
630
+ ```
631
+
632
+ ## Class / Component Relationships
633
+ ```mermaid
634
+ classDiagram
635
+ class ContactCenter
636
+ class MetricsManager
637
+ class METRIC_EVENT_NAMES
638
+ class eventTaxonomyMap
639
+ class NewMetrics
640
+ ContactCenter --> MetricsManager : timeEvent / trackEvent
641
+ MetricsManager --> METRIC_EVENT_NAMES : canonical names
642
+ MetricsManager --> eventTaxonomyMap : behavioral taxonomy lookup
643
+ MetricsManager --> NewMetrics : submit queued event types
644
+ ```
645
+
646
+ | Component | File | Responsibility |
647
+ |---|---|---|
648
+ | `MetricsManager` | `MetricsManager.ts` | Singleton that manages event queuing, timing, payload preparation, and submission |
649
+ | `BehavioralEventTaxonomy`| `behavioral-events.ts` | Maps metric event names to structured taxonomy for behavioral analytics |
650
+ | `METRIC_EVENT_NAMES` | `constants.ts` | Canonical constant object of all tracked metric event names |
651
+
652
+ `MetricsManager` uses a private constructor with a static `getInstance` factory:
653
+
654
+ ```typescript
655
+ // MetricsManager.ts
656
+ export default class MetricsManager {
657
+ private static instance: MetricsManager;
658
+ private constructor() {}
659
+
660
+ public static getInstance(options?: {webex: WebexSDK}): MetricsManager {
661
+ if (!MetricsManager.instance) {
662
+ MetricsManager.instance = new MetricsManager();
663
+ }
664
+ if (!MetricsManager.instance.webex && options?.webex) {
665
+ MetricsManager.instance.setWebex(options.webex);
666
+ }
667
+ return MetricsManager.instance;
668
+ }
669
+
670
+ public static resetInstance() {
671
+ MetricsManager.instance = undefined;
672
+ }
673
+ }
674
+ ```
675
+
676
+ - The Webex SDK instance is set once via `setWebex()`, which listens for the `ready` event before flushing pending queues.
677
+
678
+ - `resetInstance()` sets the singleton to `undefined`, allowing a fresh instance to be created. Primarily used in tests.
679
+
680
+ ## Use Cases
681
+ - **UC-1 Time and track an event:** `timeEvent` records the start against success/failure keys and `trackEvent` attaches `duration_ms` before preparing and queuing the payload. Evidence: `src/metrics/MetricsManager.ts`, `test/unit/spec/metrics/MetricsManager.ts`.
682
+ - **UC-2 Queue until SDK readiness:** events remain in the behavioral/operational/business pending queues until the host is ready, then the ready callback drains them. Evidence: `src/metrics/MetricsManager.ts`, `test/unit/spec/metrics/MetricsManager.ts`.
683
+ - **UC-3 Submit event categories:** each requested metric service uses its matching `webex.internal.newMetrics` submission method; taxonomy is applied only where `eventTaxonomyMap` contains the name. Evidence: `src/metrics/MetricsManager.ts`, `src/metrics/behavioral-events.ts`, `test/unit/spec/metrics/MetricsManager.ts`.
684
+
685
+ ```typescript
686
+ import MetricsManager from '../metrics/MetricsManager';
687
+ import {METRIC_EVENT_NAMES} from '../metrics/constants';
688
+
689
+ // Get the singleton instance (webex is set during the ContactCenter READY callback)
690
+ const metrics = MetricsManager.getInstance();
691
+
692
+ // Time an operation, then track its result
693
+ metrics.timeEvent(METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS);
694
+ // ... perform the operation ...
695
+ metrics.trackEvent(METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS, {agentId: '123'});
696
+ ```
697
+
698
+ The standard pattern used throughout the Contact Center SDK:
699
+
700
+ ```typescript
701
+ const metrics = MetricsManager.getInstance();
702
+
703
+ // 1. Start timing before the operation
704
+ metrics.timeEvent([
705
+ METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS,
706
+ METRIC_EVENT_NAMES.STATION_LOGIN_FAILED,
707
+ ]);
708
+
709
+ try {
710
+ const response = await performLogin(params);
711
+
712
+ // 2a. Track success (duration_ms auto-added)
713
+ metrics.trackEvent(METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS, {
714
+ ...MetricsManager.getCommonTrackingFieldForAQMResponse(response),
715
+ });
716
+ } catch (error) {
717
+ // 2b. Track failure (duration_ms auto-added)
718
+ metrics.trackEvent(METRIC_EVENT_NAMES.STATION_LOGIN_FAILED, {
719
+ ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error),
720
+ });
721
+ }
722
+ ```
723
+
724
+ ## State Model
725
+ MetricsManager holds three pending queues, running timing entries, a readiness flag, a submission lock, and an independent disabled flag. Host READY enables draining; disabling metrics prevents both timing and tracking and clears pending events through the configured disable path.
726
+
727
+ `preparePayload()` processes every event payload before submission:
728
+
729
+ 1. **Removes empty/null/undefined fields** — strips keys with `undefined`, `null`, `''`, any arrays, or empty objects
730
+
731
+ 2. **Converts spaces to underscores** — `spacesToUnderscore()` applied to all key names
732
+
733
+ 3. **Adds common metadata** — appends `tabHidden: document.hidden` in browser environments
734
+
735
+ ## Business Rules & Invariants
736
+ - `timeEvent` and every tracking method return immediately while metrics are disabled.
737
+ - Only names present in `eventTaxonomyMap` receive behavioral taxonomy; 73 of 82 names are mapped and the six AI Assistant plus three WebSocket names are intentionally catalogued as unmapped.
738
+ - `submittingEvents` prevents overlapping queue-drain executions.
739
+ - Authentication is inherited from the host Webex SDK's metrics client; MetricsManager owns no credentials, tokens, or authorization policy.
740
+
741
+ ## Concurrency & Reactive Flow
742
+ - Queue insertion is synchronous. Submission is gated by host readiness and the submission lock; each metric type drains through its own host method without propagating telemetry failures to product callers.
743
+
744
+ MetricsManager maintains three independent pending event queues:
745
+
746
+ | Queue | Type | Submitted Via | Name Transform | Extra Metadata |
747
+ |---|---|---|---|---|
748
+ | `pendingBehavioralEvents` | behavioral | `webex.internal.newMetrics.submitBehavioralEvent` | Taxonomy-based (`{product}.{agent}.{target}.{verb}`) | None |
749
+ | `pendingOperationalEvents` | operational | `webex.internal.newMetrics.submitOperationalEvent` | `WXCC_SDK_` prefix + uppercase (e.g. `WXCC_SDK_STATION_LOGIN_SUCCESS`) | None |
750
+ | `pendingBusinessEvents` | business | `webex.internal.newMetrics.submitBusinessEvent` | `WXCC_SDK_` prefix + uppercase (same as operational) | `metadata: {appType: 'wxcc_sdk'}` |
751
+
752
+ ## State Machine
753
+ ```mermaid
754
+ stateDiagram-v2
755
+ [*] --> Buffering
756
+ Buffering --> ReadyToSubmit: host already ready / ready event
757
+ ReadyToSubmit --> Submitting: pending events and lock acquired
758
+ Submitting --> ReadyToSubmit: queues drained and lock released
759
+ Buffering --> Disabled: setMetricsDisabled(true)
760
+ ReadyToSubmit --> Disabled: setMetricsDisabled(true)
761
+ Disabled --> Buffering: enabled before host ready
762
+ Disabled --> ReadyToSubmit: enabled after host ready
763
+ ```
764
+
765
+ - **readyToSubmitEvents**: Set to `true` only after `webex.once('ready')` fires. Events queue until then.
766
+
767
+ - **submittingEvents**: Lock flag to prevent concurrent `submitPendingEvents()` calls.
768
+
769
+ - **metricsDisabled**: When `true`, `timeEvent` and all `track*` methods return early, and `clearPendingEvents()` empties all queues.
770
+
771
+ ## Pitfalls
772
+ - `METRIC_EVENT_NAMES` and `eventTaxonomyMap` are different inventories: nine defined names intentionally have no behavioral taxonomy.
773
+ - `setMetricsDisabled(true)` clears pending queues but does not create a delivery receipt; callers must not infer that previously submitted events were accepted.
774
+ - Submission helpers hand events to `webex.internal.newMetrics` without a module-level retry/requeue policy, so telemetry must remain non-blocking and non-authoritative.
775
+
776
+ Static helper that extracts common tracking fields from an AQM failure response.
777
+
778
+ **Parameters**:
779
+
780
+ - `failureResponse` (Failure): The AQM failure response object
781
+
782
+ **Returns**: `Record<string, any>` with fields: `agentId`, `trackingId`, `notifTrackingId`, `orgId`, `failureType`, `failureReason`, `reasonCode`
783
+
784
+ MetricsManager is designed to be non-blocking. Metric failures do not propagate to callers:
785
+
786
+ - If `webex` is not yet ready, events are queued in `pendingBehavioralEvents`, `pendingOperationalEvents`, or `pendingBusinessEvents`
787
+
788
+ - Once `webex.ready` fires, all pending events are flushed
789
+
790
+ - If metrics are disabled via `setMetricsDisabled(true)`, all track methods silently return
791
+
792
+ - Invalid metric types log an error via `LoggerProxy` but do not throw
793
+
794
+ MetricsManager does not throw errors to callers. Instead:
795
+
796
+ - Invalid metric types are logged via `LoggerProxy.error`
797
+
798
+ - Empty `timeEvent` key arrays are logged and ignored
799
+
800
+ - Disabled state (`metricsDisabled`) prevents both timing and tracking and silently drops new events
801
+
802
+ - The `submittingEvents` lock prevents race conditions during concurrent submissions
803
+
804
+ Extracts: `agentId`, `trackingId`, `notifTrackingId`, `orgId`, `failureType`, `failureReason`, `reasonCode`
805
+
806
+ **Cause**: Webex SDK not yet ready when `trackEvent` is called
807
+
808
+ **Solution**: Events are automatically queued in `pending*Events` arrays and flushed once `webex.once('ready')` fires. Verify the SDK is initializing correctly.
809
+
810
+ **Cause**: `timeEvent` was not called before `trackEvent`, or the event name does not match any key in `runningEvents`
811
+
812
+ **Solution**: Ensure `timeEvent([SUCCESS_KEY, FAILURE_KEY])` is called before the operation, and that the exact `METRIC_EVENT_NAMES` constant is used in both calls.
813
+
814
+ **Cause**: `metricsDisabled` is set to `true`
815
+
816
+ **Solution**: Check if `setMetricsDisabled(true)` was called. This clears all pending queues and causes all `track*` methods to return early.
817
+
818
+ ## Module Do's / Don'ts
819
+ - DO use `METRIC_EVENT_NAMES` and the matching category submitter instead of constructing event names manually.
820
+ - DO keep timing success/failure keys together so either outcome clears the same running timer.
821
+ - DON'T add a behavioral taxonomy entry unless the backend taxonomy contract exists.
822
+ - DON'T make product behavior depend on metrics delivery.
823
+
824
+ ## Key Design Trade-off
825
+ - Telemetry is deliberately non-blocking and queue-backed so product behavior never waits for metrics; failures are logged rather than propagated.
826
+
827
+ ## Test-Case Strategy (module)
828
+ Use `test/unit/spec/metrics/MetricsManager.ts` for readiness queues, timing/tracking, disabled behavior, submission categories, and failures. Use `test/unit/spec/metrics/behavioral-events.ts` to reconcile every taxonomy-backed name. Mechanically compare the complete constant catalog with taxonomy keys so newly defined events cannot disappear from the spec.
829
+
830
+ | Behavior / Requirement | Existing test evidence | Gap |
831
+ |---|---|---|
832
+ | `METRICS-R-001` | `test/unit/spec/metrics/MetricsManager.ts` | Add a catalog parity assertion if constants change. |
833
+ | `METRICS-R-002` | `test/unit/spec/metrics/behavioral-events.ts` | Keep explicit coverage for all nine unmapped names. |
834
+ | `METRICS-R-003` | `test/unit/spec/metrics/MetricsManager.ts` | None. |
835
+ | `METRICS-R-004` | `test/unit/spec/metrics/MetricsManager.ts` | None. |
836
+ | `METRICS-R-005` | `test/unit/spec/metrics/MetricsManager.ts` | Authentication ownership is verified indirectly through the host metrics client. |
837
+
838
+ ## Traceability
839
+ - Repo architecture: `../../../ai-docs/ARCHITECTURE.md` · Registry: `../../../ai-docs/SPEC_INDEX.md`
840
+ - Coverage state and contracts baseline: `../../../.sdd/manifest.json`
841
+
842
+ - [`MetricsManager.ts`](../MetricsManager.ts) - Singleton metrics manager implementation
843
+
844
+ - [`behavioral-events.ts`](../behavioral-events.ts) - Event taxonomy mapping
845
+
846
+ - [`constants.ts`](../constants.ts) - `METRIC_EVENT_NAMES` definitions
847
+
848
+ - [`../../constants.ts`](../../constants.ts) - `PRODUCT_NAME` constant
849
+
850
+ - [`services/core/GlobalTypes.ts`](../../services/core/GlobalTypes.ts) - `Failure` type definition
851
+
852
+ - [MetricsManager.ts](../MetricsManager.ts) — Singleton metrics manager
853
+
854
+ - [behavioral-events.ts](../behavioral-events.ts) — Event taxonomy mapping
855
+
856
+ - [constants.ts](../constants.ts) — METRIC_EVENT_NAMES definitions
857
+
858
+ - [cc.ts](../../cc.ts) — Main plugin class (primary consumer)
859
+
860
+ - [constants.ts](../../constants.ts) — PRODUCT_NAME used in event prefixing