@webex/internal-plugin-metrics 3.12.0-next.55 → 3.12.0-next.56
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.
- package/.repo-context.json +466 -0
- package/.sdd/manifest.json +626 -0
- package/AGENTS.md +208 -0
- package/dist/call-diagnostic/call-diagnostic-metrics.js +26 -14
- package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
- package/dist/metrics.js +1 -1
- package/dist/metrics.types.js.map +1 -1
- package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +1 -0
- package/dist/types/metrics.types.d.ts +1 -0
- package/docs/adr/index.md +27 -0
- package/docs/architecture.md +437 -0
- package/docs/getting-started.md +131 -0
- package/docs/index.md +52 -0
- package/docs/specs/README.md +88 -0
- package/package.json +2 -2
- package/schemas/repo-context.schema.json +796 -0
- package/src/call-diagnostic/call-diagnostic-metrics.ts +27 -7
- package/src/call-diagnostic/docs/README.md +535 -0
- package/src/docs/README.md +703 -0
- package/src/metrics.types.ts +1 -0
- package/src/privacy-and-security-permission-enricher/docs/README.md +356 -0
- package/src/rtcMetrics/docs/README.md +447 -0
- package/src/unhandled-exception-telemetry/docs/README.md +536 -0
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +175 -0
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Module Spec
|
|
3
|
+
title: 'Call Analyzer diagnostics specification'
|
|
4
|
+
description: Responsibilities, boundaries, design, invariants, and verification for the Call Analyzer diagnostics module.
|
|
5
|
+
tags: [module, specification]
|
|
6
|
+
---
|
|
7
|
+
<!-- sdd-generated-metadata
|
|
8
|
+
doc_kind: module-spec
|
|
9
|
+
generated_from: module-spec@0.3.0
|
|
10
|
+
generated_by: claude-code
|
|
11
|
+
approved_by: rarajes2@cisco.com
|
|
12
|
+
updated_at: 2026-10-07T04:50:31Z
|
|
13
|
+
validation_status: pass
|
|
14
|
+
-->
|
|
15
|
+
|
|
16
|
+
# Call Analyzer diagnostics
|
|
17
|
+
|
|
18
|
+
This source-local document at `src/call-diagnostic/docs/README.md` owns the stable specification for
|
|
19
|
+
**the Call Analyzer diagnostics module**. Ground every claim in repository evidence and link to the
|
|
20
|
+
[repository architecture](../../../docs/architecture.md) instead of repeating broader facts.
|
|
21
|
+
|
|
22
|
+
Related context: [documentation index](../../../docs/index.md) ·
|
|
23
|
+
[documentation agent instructions](../../../AGENTS.md)
|
|
24
|
+
|
|
25
|
+
## Metadata
|
|
26
|
+
|
|
27
|
+
| Field | Value |
|
|
28
|
+
| ------------- | -------------------------------------------- |
|
|
29
|
+
| Owner | Cisco Webex JS SDK — telemetry |
|
|
30
|
+
| Source path | `src/call-diagnostic/` |
|
|
31
|
+
| Resource kind | module |
|
|
32
|
+
| Status | Active |
|
|
33
|
+
| Last verified | 2026-10-06 at `d6202dd73d` |
|
|
34
|
+
| Module id | `call-diagnostic` |
|
|
35
|
+
| Parent spec | [`src/docs/README.md`](../../docs/README.md) |
|
|
36
|
+
| Doc kind | Module spec |
|
|
37
|
+
| Coverage score | Pending coverage assessment |
|
|
38
|
+
| Validation status | pass (2026-10-07; validator runtime 01a1147a-c744-7083-9b15-95e91170c79a; 0 blocking, 0 important, 0 medium, 0 minor; conformance and source-fidelity gates pass, no code/spec mismatches found) |
|
|
39
|
+
|
|
40
|
+
## Applicability
|
|
41
|
+
|
|
42
|
+
Sections preceded by an `Include if` comment are conditional. Retain a
|
|
43
|
+
conditional section only when source evidence or a confirmed developer answer
|
|
44
|
+
satisfies its condition.
|
|
45
|
+
|
|
46
|
+
| Condition ID | Status | Evidence or reason | Owned section |
|
|
47
|
+
| ------------------------------------ | ---------- | -------------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
|
|
48
|
+
| `module.has_tiers` | N/A | The repository defines no operational or review tier policy for modules | Tier |
|
|
49
|
+
| `module.has_ui` | N/A | The module renders nothing | UI use-case flow |
|
|
50
|
+
| `module.crosses_service_boundaries` | Applicable | `src/call-diagnostic/call-diagnostic-metrics-batcher.ts` posts to the Webex metrics service | Cross-boundary use-case flow |
|
|
51
|
+
| `module.holds_client_state` | Applicable | Latency ledger in `src/call-diagnostic/call-diagnostic-metrics-latencies.ts`; delayed queues and limits in `src/call-diagnostic/call-diagnostic-metrics.ts` | Client state model |
|
|
52
|
+
| `module.enforces_domain_rules` | Applicable | Error-code mapping in `src/call-diagnostic/config.ts`; event limits and sanitization in `src/call-diagnostic/call-diagnostic-metrics.ts` | Business rules and invariants |
|
|
53
|
+
| `module.is_concurrent_async` | Applicable | Batched asynchronous submission and the deferred delayed-event flush | Concurrency and reactive flow |
|
|
54
|
+
| `module.owns_persistence` | N/A | No store, schema or migration; every structure is in-memory | Data, schema, and migration |
|
|
55
|
+
| `module.stateful_transitions` | Applicable | Delayed and immediate submission modes, and the Locus sync record lifecycle in `src/call-diagnostic/call-diagnostic-metrics-latencies.ts` | State machine |
|
|
56
|
+
| `module.exposes_wire_protocol` | Applicable | The diagnostic event envelope built in `src/call-diagnostic/call-diagnostic-metrics.ts` | Protocol and wire format |
|
|
57
|
+
| `module.ui_multi_screen` | N/A | No user interface | UI flow |
|
|
58
|
+
| `module.large_data_model` | N/A | The event model is owned externally by the Call Analyzer schema and only derived here | Data model |
|
|
59
|
+
| `module.returns_caller_errors` | Applicable | Event preparation throws when no call identity is supplied or when client type is unresolved | Caller-visible failure modes |
|
|
60
|
+
| `module.module_specific_conventions` | Applicable | Error-classification order and the empty-key sanitization exemption for media quality events | Module-specific rules |
|
|
61
|
+
| `module.published_package` | Applicable | The metrics class, latency class, utilities and config are re-exported from `src/index.ts` | Export stability |
|
|
62
|
+
| `module.embedded_in_host` | N/A | Not registered as a plugin; constructed by `src/new-metrics.ts` | Host integration and theming |
|
|
63
|
+
| `module.has_design_tradeoff` | Applicable | Delayed submission with preserved trigger time, and a fixed-priority error classification chain | Key design trade-off |
|
|
64
|
+
| `module.has_submodules` | N/A | Derived from the manifest module tree: this module has no child modules | Sub-modules |
|
|
65
|
+
|
|
66
|
+
## Evidence register
|
|
67
|
+
|
|
68
|
+
| Evidence | What it establishes |
|
|
69
|
+
| --------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
|
|
70
|
+
| `src/call-diagnostic/call-diagnostic-metrics.ts` | Event construction, origin and identifier resolution, error-payload generation, event limits, delayed submission and the fetch path |
|
|
71
|
+
| `src/call-diagnostic/call-diagnostic-metrics-latencies.ts` | The latency timestamp ledger, precomputed latencies and the Locus sync latency record lifecycle |
|
|
72
|
+
| `src/call-diagnostic/call-diagnostic-metrics.util.ts` | IP anonymization, empty-key sanitization, error classifiers, build-type detection and the batch preparation step |
|
|
73
|
+
| `src/call-diagnostic/call-diagnostic-metrics-batcher.ts` | The transport to the client-metrics resource, the send-time stamp and the batch log lines |
|
|
74
|
+
| `src/call-diagnostic/config.ts` | Client error codes, the service-to-client error map, the client error payload catalog and the log prefixes |
|
|
75
|
+
| `src/prelogin-metrics-batcher.ts` | The unauthenticated pre-login transport this module uses when a pre-login identifier is supplied |
|
|
76
|
+
| `src/new-metrics.ts` | How the façade constructs this module, records timestamps and forwards delay state |
|
|
77
|
+
| `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | Behavioral verification of origin, identifiers, submission routing, event limits, error payloads, delayed events and the fetch path |
|
|
78
|
+
| `test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts` | Verification of timestamp rules, clamping and Locus sync skew, TTL and cap behavior |
|
|
79
|
+
| `test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts` | Verification of sanitization, classifiers, build type and the join-time attachment in batch preparation |
|
|
80
|
+
| `test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts` | Verification of the batcher's request, success and failure paths |
|
|
81
|
+
|
|
82
|
+
## Purpose and boundary
|
|
83
|
+
|
|
84
|
+
- Responsibility: building, enriching and submitting Call Analyzer events — client events, feature
|
|
85
|
+
events and media quality events — and maintaining the latency ledger from which join-time metrics
|
|
86
|
+
are derived.
|
|
87
|
+
- In scope: origin and identifier resolution; converting raw errors into Call Analyzer error
|
|
88
|
+
payloads; per-call limits on repetitive events; delayed submission; join-time and media setup
|
|
89
|
+
latency calculation; Locus sync latency records; the authenticated and pre-login submission paths;
|
|
90
|
+
and pre-built fetch options for submission during page unload.
|
|
91
|
+
- Out of scope: the event names and payload fields themselves, which the external Call Analyzer
|
|
92
|
+
schema owns; deciding when an event happens, which belongs to the meetings and calling layers;
|
|
93
|
+
and permission enrichment, which the sibling enricher module applies before events reach here.
|
|
94
|
+
- Consumers: `src/new-metrics.ts`, which owns the single instance of each class. The meetings plugin
|
|
95
|
+
and the device plugin reach the same instance through the façade, the latter to inject device
|
|
96
|
+
details. The classes, utilities and config are also exported from `src/index.ts`.
|
|
97
|
+
|
|
98
|
+
## Structure and key files
|
|
99
|
+
|
|
100
|
+
| Path | Responsibility |
|
|
101
|
+
| ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------- |
|
|
102
|
+
| `src/call-diagnostic/call-diagnostic-metrics.ts` | The event builder and submitter; authoritative for envelope shape, routing, limits, error payloads and delay handling |
|
|
103
|
+
| `src/call-diagnostic/call-diagnostic-metrics-latencies.ts` | The latency ledger and every derived join-time calculation; authoritative for which timestamps are kept and how latencies clamp |
|
|
104
|
+
| `src/call-diagnostic/call-diagnostic-metrics.util.ts` | Stateless helpers and the batch preparation step that attaches join times and origin defaults |
|
|
105
|
+
| `src/call-diagnostic/call-diagnostic-metrics-batcher.ts` | The batcher bound to the client-metrics resource |
|
|
106
|
+
| `src/call-diagnostic/config.ts` | Error code constants, the service-to-client map and the client error payload catalog |
|
|
107
|
+
|
|
108
|
+
## Public surface
|
|
109
|
+
|
|
110
|
+
| Surface | Consumer | Compatibility commitment | Source |
|
|
111
|
+
| ----------------------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------- |
|
|
112
|
+
| `submitClientEvent` | `src/new-metrics.ts` | Queues when delay is requested; otherwise builds, limits and submits. Throws when no call identity is given | `src/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
113
|
+
| `submitFeatureEvent` | `src/new-metrics.ts` | In-meeting only; submitted as a business-typed envelope | `src/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
114
|
+
| `submitMQE` | `src/new-metrics.ts` | In-meeting only; exempt from empty-key sanitization | `src/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
115
|
+
| `submitDelayedClientEvents`, `submitDelayedClientFeatureEvents` | `src/new-metrics.ts` | Submit every queued event with optional overrides, then empty the queue | `src/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
116
|
+
| `buildClientEventFetchRequestOptions` | `src/new-metrics.ts` | Returns fetch options for the client-metrics or pre-login resource without submitting | `src/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
117
|
+
| `getErrorPayloadForClientErrorCode`, `generateClientEventErrorPayload`, `isServiceErrorExpected` | Meetings plugin, through the façade | Map raw errors and codes to catalog payloads; the second caches by error object | `src/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
118
|
+
| Event-limit, opt-out, Mercury status and device setters | Meetings and device plugins, through the façade | Mutate per-instance state consulted at build time | `src/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
119
|
+
| `validator` | Overridable by callers | Called with each built event before submission; the default accepts everything | `src/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
120
|
+
| `CallDiagnosticLatencies` | `src/new-metrics.ts`, meetings plugin | Timestamp, latency and Locus sync operations plus the derived join-time getters | `src/call-diagnostic/call-diagnostic-metrics-latencies.ts` |
|
|
121
|
+
| `CALL_DIAGNOSTIC_CONFIG`, `CallDiagnosticUtils` | Meetings plugin | Re-exported constants and helpers; codes and catalog entries are a wire-level contract | `src/index.ts` |
|
|
122
|
+
|
|
123
|
+
Event names and payload fields are not restated here; they are derived from the external Call
|
|
124
|
+
Analyzer schema through `src/metrics.types.ts`.
|
|
125
|
+
|
|
126
|
+
## Dependencies
|
|
127
|
+
|
|
128
|
+
| Dependency | Why it is required | Failure behavior |
|
|
129
|
+
| ------------------------------------------- | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
130
|
+
| `@webex/webex-core` `StatelessWebexPlugin`, `WebexPlugin`, `Batcher` | Base classes and the batched transport | Network errors re-enqueue with backoff in the parent batcher; other errors reject the queued item |
|
|
131
|
+
| Meetings plugin, through the SDK instance | Basic meeting information, geo hint, configuration and stats analyzer | A missing meeting records a failed-to-send client metric and the event is not built |
|
|
132
|
+
| Device plugin, injected via `setDeviceInfo` | Device URL, organization, user and installation identifiers | Absent device falls back to the credentials user identifier, then to the pre-login identifier |
|
|
133
|
+
| `src/prelogin-metrics-batcher.ts` | The unauthenticated pre-login transport | Rejects when no pre-login identifier was saved |
|
|
134
|
+
| `src/metrics.js` `submitClientMetrics` | Records the failed-to-send metric when a meeting cannot be found | Fire-and-forget; its result is not observed |
|
|
135
|
+
| `@webex/event-dictionary-ts`, through `src/metrics.types.ts` | The authoritative event schema | A schema change surfaces at build time |
|
|
136
|
+
| `ip-anonymize`, `lodash`, `uuid` | Address truncation, deep merge and empty-key checks, event identifiers | A failed anonymization yields undefined and the field is dropped |
|
|
137
|
+
|
|
138
|
+
## Requirements
|
|
139
|
+
|
|
140
|
+
| ID | WHAT | WHY | Source evidence | Test or example evidence | Assumptions or gaps | Confidence |
|
|
141
|
+
| --------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------ | --------------------------------------------------------------------- | ------------------- | ---------- |
|
|
142
|
+
| `MOD-001` | A client event is built in-meeting when a meeting identifier is supplied, pre-meeting when only a correlation identifier is supplied, and otherwise preparation throws | Call Analyzer correlates every event to one call; an event with no call identity cannot be attributed | `src/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none | Present |
|
|
143
|
+
| `MOD-002` | When a meeting identifier is supplied but the meeting cannot be found, a failed-to-send client metric is recorded instead of the event | The lost event must remain visible as a count rather than disappearing silently | `src/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none | Present |
|
|
144
|
+
| `MOD-003` | Origin requires a client type and sub-client type, from options or from meetings configuration, and throws when neither supplies both | Call Analyzer segments every event by client; an unclassified event is unusable | `src/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none | Present |
|
|
145
|
+
| `MOD-004` | Public and local network prefixes are anonymized before they enter the origin | Raw IP addresses are personal data | `src/call-diagnostic/call-diagnostic-metrics.util.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none | Present |
|
|
146
|
+
| `MOD-005` | The user identifier resolves from the device, then from credentials, then from the pre-login identifier | An event must carry the most authoritative identity available at the time it fires, including before device registration | `src/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none | Present |
|
|
147
|
+
| `MOD-006` | Empty keys are removed from client and feature events but not from media quality events | Call Analyzer rejects empty properties, while media quality intervals legitimately carry zeros and empty arrays that must be preserved | `src/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none | Present |
|
|
148
|
+
| `MOD-007` | Media render, receive and transmit start/stop events are sent at most once per correlation identifier and media type, or per share instance for share media | These events can fire repeatedly during one call and would otherwise flood Call Analyzer with duplicates | `src/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none | Present |
|
|
149
|
+
| `MOD-008` | ROAP message sent/received events are sent at most once per correlation identifier and ROAP message type | Repeated renegotiation would otherwise produce duplicate events of no extra diagnostic value | `src/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none | Present |
|
|
150
|
+
| `MOD-009` | Event limits can be cleared for all calls or for one correlation identifier only | A rejoin must reset its own limits without unblocking another concurrent call's limited events | `src/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none | Present |
|
|
151
|
+
| `MOD-010` | A raw error is classified in fixed priority order — browser media error, SDP offer failure, mapped service code, Locus 429/503, Locus service code, meeting info, network, unauthorized, then unknown | The first matching classifier wins, so the most specific diagnosis must be tried first | `src/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none | Present |
|
|
152
|
+
| `MOD-011` | A Locus HTTP 429 or 503 maps to the rate-limited or unavailable client code only when no earlier classifier matched and the raw error's request `uri` or `url` contains the literal substring `locus` | The same HTTP status from another service has a different meaning and must not be reported as a Locus condition; the check is a substring match, not a parsed host comparison | `src/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | Any URL containing `locus` anywhere, including in a path or query, also matches | Present |
|
|
153
|
+
| `MOD-012` | A generated error payload is cached per raw error object | The same error is often reported by several events in one failure; reclassifying it each time is wasted work and the cache flag is logged for diagnosis | `src/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none | Present |
|
|
154
|
+
| `MOD-013` | With delay enabled, client and feature events are queued with their original trigger time and submitted later with optional overrides | Events raised before the call's identity is known can be submitted once it is, without losing when they actually happened | `src/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none | Present |
|
|
155
|
+
| `MOD-014` | A client event with a pre-login identifier is submitted through the unauthenticated pre-login transport | Join flows that start before sign-in must still be diagnosable | `src/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none | Present |
|
|
156
|
+
| `MOD-015` | Client events are typed as diagnostic events and feature events as business events in the submitted envelope | Ingestion routes the two families to different stores | `src/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none | Present |
|
|
157
|
+
| `MOD-016` | Batch preparation attaches the join-time and media setup latencies that belong to each milestone event | Join-time metrics are only meaningful on the milestone that ends the measured span | `src/call-diagnostic/call-diagnostic-metrics.util.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts` | none | Present |
|
|
158
|
+
| `MOD-017` | Repeating milestones keep only their first timestamp, and a new local SDP resets the remote SDP timestamp | Retries and renegotiation would otherwise overwrite the start of the span being measured | `src/call-diagnostic/call-diagnostic-metrics-latencies.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts` | none | Present |
|
|
159
|
+
| `MOD-018` | Derived latencies are clamped to a non-negative 32-bit range | Clock jumps and missing timestamps must not produce negative or overflowing values in ingestion | `src/call-diagnostic/call-diagnostic-metrics-latencies.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts` | none | Present |
|
|
160
|
+
| `MOD-019` | A Locus sync record with any segment beyond the skew threshold is discarded; incomplete records expire after their TTL and are capped per dataset | Sleep and wake clock jumps corrupt sync timings, and churn must not grow memory without bound | `src/call-diagnostic/call-diagnostic-metrics-latencies.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts` | none | Present |
|
|
161
|
+
| `MOD-020` | Fetch options can be pre-built for a client event and later re-timed so triggered and sent times equal the moment of submission | During page unload the normal asynchronous path cannot complete; a keep-alive fetch must fire immediately with correct times | `src/call-diagnostic/call-diagnostic-metrics.util.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none | Present |
|
|
162
|
+
| `MOD-021` | A service error code is reported as expected only when its mapped catalog payload is in the expected category | Callers use this to keep expected failures out of error dashboards | `src/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none | Present |
|
|
163
|
+
|
|
164
|
+
## Design overview
|
|
165
|
+
|
|
166
|
+
The module is three cooperating pieces owned by the façade: an event builder, a latency ledger, and
|
|
167
|
+
a batcher.
|
|
168
|
+
|
|
169
|
+
**The event builder** (`src/call-diagnostic/call-diagnostic-metrics.ts`) turns a name, a partial
|
|
170
|
+
payload and options into a complete Call Analyzer event. Every event family goes through the same
|
|
171
|
+
two stages: a family-specific object is built — in-meeting, pre-meeting or media-quality — and is
|
|
172
|
+
then wrapped by `prepareDiagnosticEvent`, which adds the event identifier, version, origin, trigger
|
|
173
|
+
time and sender country, and sanitizes empty keys for every family except media quality. Caller
|
|
174
|
+
payloads are deep-merged last, so a caller can override any computed field.
|
|
175
|
+
|
|
176
|
+
Origin and identifiers are resolved from the host on every event rather than cached, because they
|
|
177
|
+
change during a call: the meeting gains a Locus URL and conference identifiers, the device registers,
|
|
178
|
+
the user signs in. The identifier chain prefers the most authoritative source available and falls
|
|
179
|
+
back gracefully down to a pre-login identifier.
|
|
180
|
+
|
|
181
|
+
Errors are classified once and cached. `generateClientEventErrorPayload` walks a fixed-priority chain
|
|
182
|
+
of classifiers and stops at the first match; each match resolves a client error code that indexes the
|
|
183
|
+
payload catalog in `src/call-diagnostic/config.ts`. The order is the design: the most specific
|
|
184
|
+
diagnosis is tried first and the unknown code is only the last resort.
|
|
185
|
+
|
|
186
|
+
Submission is gated twice. Delay mode queues the call arguments, not a built event, together with
|
|
187
|
+
the original trigger time, so the event is built later with the identity known by then. The event
|
|
188
|
+
limiter then suppresses repeats of a small set of high-frequency media and ROAP events per call.
|
|
189
|
+
|
|
190
|
+
**The latency ledger** (`src/call-diagnostic/call-diagnostic-metrics-latencies.ts`) records a
|
|
191
|
+
timestamp for every event name the façade sees, plus precomputed latencies measured elsewhere. Join
|
|
192
|
+
time metrics are differences between pairs of timestamps, clamped, and are attached to the milestone
|
|
193
|
+
events during batch preparation rather than at build time. Locus sync latencies are a separate,
|
|
194
|
+
record-per-sync lifecycle keyed by meeting, dataset and tracking identifier, with skew rejection, a
|
|
195
|
+
pending TTL and a per-dataset cap.
|
|
196
|
+
|
|
197
|
+
**The batcher** (`src/call-diagnostic/call-diagnostic-metrics-batcher.ts`) inherits queueing and
|
|
198
|
+
backoff from `src/batcher.js`, runs the shared preparation step, stamps the send time on each item and
|
|
199
|
+
posts to the client-metrics resource.
|
|
200
|
+
|
|
201
|
+
## Data flow and sequence coverage
|
|
202
|
+
|
|
203
|
+
Collection is an in-process method call; submission is a batched HTTP POST through the host request
|
|
204
|
+
pipeline. There are four operation groups, diagrammed separately where actor order or outcome differs.
|
|
205
|
+
|
|
206
|
+
| Operation group | Entry and outcome | Diagram or evidence | Failure and recovery coverage |
|
|
207
|
+
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
208
|
+
| Submit a client or feature event | The façade forwards an event; it is queued when delayed, otherwise built, limited and batched | First sequence diagram below | Missing call identity throws; missing meeting records a failed-to-send metric; a limited event resolves unsent |
|
|
209
|
+
| Flush delayed events | Delay is disabled; every queued event is re-submitted with overrides and the queue empties | Second sequence diagram below | Each re-submission follows the first group's failure paths independently |
|
|
210
|
+
| Submit a media quality event | The façade forwards interval statistics for a meeting; the event is built unsanitized and batched | `src/call-diagnostic/call-diagnostic-metrics.ts` | No meeting identifier throws; a missing meeting records a failed-to-send metric |
|
|
211
|
+
| Unload-time fetch | Options are pre-built, then re-timed and fired with a keep-alive fetch | Third sequence diagram below | Not retried; the page is unloading |
|
|
212
|
+
|
|
213
|
+
```mermaid
|
|
214
|
+
sequenceDiagram
|
|
215
|
+
participant Facade as newMetrics facade
|
|
216
|
+
participant CD as CallDiagnosticMetrics
|
|
217
|
+
participant Host as Meetings and device state
|
|
218
|
+
participant Limiter as Event limiter
|
|
219
|
+
participant Batcher as Call diagnostic batcher
|
|
220
|
+
participant Svc as Webex metrics service
|
|
221
|
+
Facade->>CD: submitClientEvent(name, payload, options, delay)
|
|
222
|
+
alt delay requested
|
|
223
|
+
CD->>CD: queue arguments with the current trigger time
|
|
224
|
+
CD-->>Facade: resolve
|
|
225
|
+
else immediate
|
|
226
|
+
opt raw error supplied
|
|
227
|
+
CD->>CD: classify error, or reuse cached payload
|
|
228
|
+
end
|
|
229
|
+
alt meeting identifier
|
|
230
|
+
CD->>Host: read meeting, identifiers and origin
|
|
231
|
+
opt meeting not found
|
|
232
|
+
CD->>Facade: record failed-to-send metric
|
|
233
|
+
end
|
|
234
|
+
else correlation identifier only
|
|
235
|
+
CD->>Host: read pre-meeting identifiers and origin
|
|
236
|
+
else no call identity
|
|
237
|
+
CD-->>Facade: throw
|
|
238
|
+
end
|
|
239
|
+
CD->>CD: merge caller payload, wrap envelope, remove empty keys
|
|
240
|
+
CD->>Limiter: should this event be sent
|
|
241
|
+
alt limit reached
|
|
242
|
+
CD-->>Facade: resolve without sending
|
|
243
|
+
else pre-login identifier supplied
|
|
244
|
+
CD->>Batcher: pre-login batcher request
|
|
245
|
+
else authenticated
|
|
246
|
+
CD->>Batcher: request diagnostic-event envelope
|
|
247
|
+
end
|
|
248
|
+
Batcher->>Batcher: attach join times, stamp sent time
|
|
249
|
+
Batcher->>Svc: POST clientmetrics
|
|
250
|
+
opt network error
|
|
251
|
+
Batcher->>Batcher: re-enqueue with doubling delay
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
```mermaid
|
|
257
|
+
sequenceDiagram
|
|
258
|
+
participant Facade as newMetrics facade
|
|
259
|
+
participant CD as CallDiagnosticMetrics
|
|
260
|
+
Facade->>CD: submitDelayedClientEvents(overrides)
|
|
261
|
+
alt queue is empty
|
|
262
|
+
CD-->>Facade: resolve
|
|
263
|
+
else queued events
|
|
264
|
+
loop for each queued event
|
|
265
|
+
CD->>CD: submitClientEvent with options merged with overrides
|
|
266
|
+
end
|
|
267
|
+
CD->>CD: empty the queue
|
|
268
|
+
CD-->>Facade: resolve when all submissions settle
|
|
269
|
+
end
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
```mermaid
|
|
273
|
+
sequenceDiagram
|
|
274
|
+
participant Client as First party client
|
|
275
|
+
participant Facade as newMetrics facade
|
|
276
|
+
participant CD as CallDiagnosticMetrics
|
|
277
|
+
participant Core as WebexCore
|
|
278
|
+
Client->>Facade: buildClientEventFetchRequestOptions
|
|
279
|
+
Facade->>CD: build event and prepare it as a batch item
|
|
280
|
+
CD->>Core: prepareFetchOptions for clientmetrics or clientmetrics-prelogin
|
|
281
|
+
Core-->>Client: fetch options
|
|
282
|
+
Note over Client: later, on beforeunload
|
|
283
|
+
Client->>Facade: setMetricTimingsAndFetch(options)
|
|
284
|
+
Facade->>Facade: set triggered and sent to now
|
|
285
|
+
Facade->>Core: setTimingsAndFetch with keep-alive
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Class and component relationships
|
|
289
|
+
|
|
290
|
+
```mermaid
|
|
291
|
+
classDiagram
|
|
292
|
+
class NewMetrics
|
|
293
|
+
class CallDiagnosticMetrics {
|
|
294
|
+
-callDiagnosticEventsBatcher
|
|
295
|
+
-preLoginMetricsBatcher
|
|
296
|
+
-delayedClientEvents
|
|
297
|
+
-delayedClientFeatureEvents
|
|
298
|
+
-eventErrorCache
|
|
299
|
+
-eventLimitTracker
|
|
300
|
+
+validator
|
|
301
|
+
+submitClientEvent()
|
|
302
|
+
+submitFeatureEvent()
|
|
303
|
+
+submitMQE()
|
|
304
|
+
+generateClientEventErrorPayload()
|
|
305
|
+
+buildClientEventFetchRequestOptions()
|
|
306
|
+
}
|
|
307
|
+
class CallDiagnosticLatencies {
|
|
308
|
+
+latencyTimestamps
|
|
309
|
+
+precomputedLatencies
|
|
310
|
+
+meetingLatencies
|
|
311
|
+
+saveTimestamp()
|
|
312
|
+
+saveLatency()
|
|
313
|
+
+getLocusSyncLatency()
|
|
314
|
+
}
|
|
315
|
+
class CallDiagnosticEventsBatcher
|
|
316
|
+
class PreLoginMetricsBatcher
|
|
317
|
+
class MetricsBatcher
|
|
318
|
+
class CallDiagnosticUtils {
|
|
319
|
+
+prepareDiagnosticMetricItem()
|
|
320
|
+
+anonymizeIPAddress()
|
|
321
|
+
+clearEmptyKeysRecursively()
|
|
322
|
+
}
|
|
323
|
+
NewMetrics --> CallDiagnosticMetrics : owns
|
|
324
|
+
NewMetrics --> CallDiagnosticLatencies : owns
|
|
325
|
+
CallDiagnosticMetrics --> CallDiagnosticEventsBatcher : authenticated path
|
|
326
|
+
CallDiagnosticMetrics --> PreLoginMetricsBatcher : pre-login path
|
|
327
|
+
CallDiagnosticEventsBatcher --|> MetricsBatcher
|
|
328
|
+
PreLoginMetricsBatcher --|> MetricsBatcher
|
|
329
|
+
CallDiagnosticEventsBatcher --> CallDiagnosticUtils : prepares items
|
|
330
|
+
CallDiagnosticUtils --> CallDiagnosticLatencies : reads join times
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
## Use cases and flows
|
|
334
|
+
|
|
335
|
+
| Use case | Actor or caller | Primary steps and outcome | Failure or boundary behavior | Evidence |
|
|
336
|
+
| -------- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
337
|
+
| `UC-001` | Meetings plugin | A join milestone event is submitted in-meeting; identifiers and origin are resolved, the event is batched and join times are attached | A missing meeting records a failed-to-send metric instead | `src/call-diagnostic/call-diagnostic-metrics.ts`, `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
338
|
+
| `UC-002` | Meetings plugin | A join fails with a raw error; the error is classified into a catalog payload and attached to the event | An unrecognized error falls back to the unknown code, carrying the service code and name | `src/call-diagnostic/call-diagnostic-metrics.ts`, `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
339
|
+
| `UC-003` | Media layer | Media transmit start fires repeatedly for one call and media type; only the first is sent | Clearing limits for the correlation identifier allows the next one through | `src/call-diagnostic/call-diagnostic-metrics.ts`, `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
340
|
+
| `UC-004` | First party client | Events fire before the call identity is known with delay enabled; disabling delay submits them with overrides and original trigger times | An empty queue submits nothing | `src/call-diagnostic/call-diagnostic-metrics.ts`, `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
341
|
+
| `UC-005` | Guest before sign-in | A pre-join event carries a pre-login identifier and is posted to the unauthenticated resource | The pre-login batcher rejects when no identifier is saved | `src/call-diagnostic/call-diagnostic-metrics.ts`, `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
342
|
+
| `UC-006` | First party client | The tab is closing; pre-built fetch options are re-timed and fired with keep-alive | No retry; the page is unloading | `src/call-diagnostic/call-diagnostic-metrics.util.ts`, `test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts` |
|
|
343
|
+
| `UC-007` | Meetings plugin | Locus sync milestones are recorded; a complete record yields sync latencies | A skewed record is discarded; an incomplete one expires after its TTL | `src/call-diagnostic/call-diagnostic-metrics-latencies.ts`, `test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts` |
|
|
344
|
+
|
|
345
|
+
<!-- Include if: the module calls another service or crosses an event or network boundary. [condition-id: module.crosses_service_boundaries] -->
|
|
346
|
+
|
|
347
|
+
### Cross-boundary use-case flow
|
|
348
|
+
|
|
349
|
+
- Boundary and transport: HTTPS POST to the `metrics` service, resource `clientmetrics`, or
|
|
350
|
+
`clientmetrics-prelogin` with authorization disabled and the pre-login header. The unload path uses
|
|
351
|
+
a keep-alive fetch prepared by the host.
|
|
352
|
+
- Ordering: items are batched in arrival order; no cross-batch ordering is promised. Each event
|
|
353
|
+
carries its own trigger time, and delayed events keep the time they were first raised.
|
|
354
|
+
- Compatibility: event names and fields are owned by the external Call Analyzer schema; error codes
|
|
355
|
+
and catalog entries in `src/call-diagnostic/config.ts` are a wire-level contract with Call Analyzer.
|
|
356
|
+
- Timeout and retry: network errors re-enqueue with doubling delay up to the configured plateau in the
|
|
357
|
+
parent batcher; other HTTP errors reject the item and are logged with a batch identifier.
|
|
358
|
+
- Recovery: none beyond batcher backoff. A rejected item is lost.
|
|
359
|
+
|
|
360
|
+
<!-- Include if: the module holds client-side state. [condition-id: module.holds_client_state] -->
|
|
361
|
+
|
|
362
|
+
## Client state model
|
|
363
|
+
|
|
364
|
+
| State or slice | Owner | Initial state | Transition triggers | Reset or persistence boundary |
|
|
365
|
+
| --------------------------- | -------------------------- | ------------- | --------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
|
366
|
+
| Latency timestamps | `CallDiagnosticLatencies` | Empty map | Every event name recorded through the façade | Cleared by the internal join-latency reset event |
|
|
367
|
+
| Precomputed latencies | `CallDiagnosticLatencies` | Empty map | Latencies measured elsewhere and saved, optionally accumulated | Cleared with the timestamps |
|
|
368
|
+
| Locus sync records | `CallDiagnosticLatencies` | Empty map | Sync milestones per meeting, dataset and tracking identifier | Consumed on completion; discarded on skew; pruned by TTL; capped per dataset |
|
|
369
|
+
| Delayed client and feature events | `CallDiagnosticMetrics` | Empty arrays | Submissions while delay is enabled | Emptied when delayed events are submitted |
|
|
370
|
+
| Event-limit counters | `CallDiagnosticMetrics` | Empty map | A limited event is sent | Cleared wholesale or per correlation identifier |
|
|
371
|
+
| Error payload cache | `CallDiagnosticMetrics` | Empty `WeakMap` | A raw error is classified | Garbage-collected with the error, or cleared explicitly |
|
|
372
|
+
| Device, opt-out and Mercury status | `CallDiagnosticMetrics` | Unset or false | Setters called by the device and meetings plugins | Instance lifetime |
|
|
373
|
+
|
|
374
|
+
<!-- Include if: the module enforces domain rules or entity invariants. [condition-id: module.enforces_domain_rules] -->
|
|
375
|
+
|
|
376
|
+
## Business rules and invariants
|
|
377
|
+
|
|
378
|
+
| ID | Invariant | WHY | Enforcement source | Test evidence |
|
|
379
|
+
| --------- | -------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------- | --------------------------------------------------------------------- |
|
|
380
|
+
| `INV-001` | No event is built without a call identity and a classified client | Call Analyzer cannot attribute or segment such an event | `src/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
381
|
+
| `INV-002` | No raw IP address reaches the origin | IP addresses are personal data | `src/call-diagnostic/call-diagnostic-metrics.util.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
382
|
+
| `INV-003` | Every classified error resolves to a catalog payload, ending in the unknown code | An error event without an error code is undiagnosable | `src/call-diagnostic/config.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
383
|
+
| `INV-004` | Limited events are sent at most once per limit key | Prevents duplicate high-frequency events per call | `src/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
384
|
+
| `INV-005` | Media quality events are never empty-key sanitized | Zero and empty interval values are meaningful | `src/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
385
|
+
| `INV-006` | Derived latencies are clamped to a non-negative 32-bit integer range | Ingestion must not receive negative or overflowing durations | `src/call-diagnostic/call-diagnostic-metrics-latencies.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts` |
|
|
386
|
+
| `INV-007` | Locus sync records per meeting and dataset never exceed the cap | Bounds memory under sync churn | `src/call-diagnostic/call-diagnostic-metrics-latencies.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts` |
|
|
387
|
+
|
|
388
|
+
<!-- Include if: the module is concurrent, asynchronous, reactive, or event-driven. [condition-id: module.is_concurrent_async] -->
|
|
389
|
+
|
|
390
|
+
## Concurrency and reactive flow
|
|
391
|
+
|
|
392
|
+
- Execution model: synchronous event building on the caller's turn, then asynchronous batched
|
|
393
|
+
submission through the `Batcher` queue inherited from `src/batcher.js`.
|
|
394
|
+
- Ordering guarantees: none across batches. Within a batch items keep arrival order. Delayed events
|
|
395
|
+
are re-submitted in queue order but settle independently.
|
|
396
|
+
- Idempotency and retry: each event has a fresh identifier, so a re-enqueued item is the same event,
|
|
397
|
+
not a duplicate. The event limiter is the only deduplication, and it is per limit key.
|
|
398
|
+
- Shared-state protection: single-threaded. All maps are mutated synchronously on the caller's turn.
|
|
399
|
+
- Blocking restrictions: event building must stay synchronous so the unload path can prepare options
|
|
400
|
+
in time; only the transport is asynchronous.
|
|
401
|
+
|
|
402
|
+
<!-- Include if: the module has non-trivial state transitions. [condition-id: module.stateful_transitions] -->
|
|
403
|
+
|
|
404
|
+
## State machine
|
|
405
|
+
|
|
406
|
+
Two lifecycles matter: the façade-controlled submission mode, and one Locus sync latency record.
|
|
407
|
+
|
|
408
|
+
```mermaid
|
|
409
|
+
stateDiagram-v2
|
|
410
|
+
state "Submission mode" as Mode {
|
|
411
|
+
[*] --> Immediate
|
|
412
|
+
Immediate --> Delayed: delay enabled
|
|
413
|
+
Delayed --> Delayed: event queued with trigger time
|
|
414
|
+
Delayed --> Immediate: delay disabled, queue submitted with overrides and emptied
|
|
415
|
+
}
|
|
416
|
+
state "Locus sync record" as Sync {
|
|
417
|
+
[*] --> Pending: first sync milestone
|
|
418
|
+
Pending --> Pending: further milestones recorded
|
|
419
|
+
Pending --> Completed: sync response and message received both present
|
|
420
|
+
Completed --> Reported: latencies read and record consumed
|
|
421
|
+
Completed --> Discarded: a segment exceeds the skew threshold
|
|
422
|
+
Pending --> Discarded: older than the pending TTL, over the per-dataset cap, or cleared by tracking id
|
|
423
|
+
Reported --> [*]
|
|
424
|
+
Discarded --> [*]
|
|
425
|
+
}
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
Rejected transitions: delayed events are never submitted while the façade is not ready; a sync record
|
|
429
|
+
missing a required milestone is never reported, it returns undefined and is cleared.
|
|
430
|
+
|
|
431
|
+
<!-- Include if: callers depend on a wire protocol or serialized format. [condition-id: module.exposes_wire_protocol] -->
|
|
432
|
+
|
|
433
|
+
## Protocol and wire format
|
|
434
|
+
|
|
435
|
+
| Message or frame | Version | Producer or serializer | Consumer or parser | Compatibility and ordering rule |
|
|
436
|
+
| ---------------------------- | ------- | --------------------------------------------------------- | ------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
437
|
+
| Diagnostic event envelope | `1` | `src/call-diagnostic/call-diagnostic-metrics.ts` | Webex Call Analyzer | Fields are owned by the external schema; the envelope type tag is `diagnostic-event` |
|
|
438
|
+
| Feature event envelope | `1` | `src/call-diagnostic/call-diagnostic-metrics.ts` | Webex business metrics | Same envelope with the `business` type tag |
|
|
439
|
+
| Client error payload | n/a | `src/call-diagnostic/config.ts` | Webex Call Analyzer | Codes and categories are a shared vocabulary; changing a mapping changes dashboards |
|
|
440
|
+
| Batch body | n/a | `src/call-diagnostic/call-diagnostic-metrics-batcher.ts` | Webex metrics service | A `metrics` array; the send time is stamped per item immediately before posting |
|
|
441
|
+
|
|
442
|
+
The envelope is declared through `src/metrics.types.ts`; it is not restated here.
|
|
443
|
+
|
|
444
|
+
<!-- Include if: the module returns or raises errors callers must handle. [condition-id: module.returns_caller_errors] -->
|
|
445
|
+
|
|
446
|
+
## Caller-visible failure modes
|
|
447
|
+
|
|
448
|
+
| Condition | Signal or result | Caller behavior | Retry or recovery | Evidence |
|
|
449
|
+
| ----------------------------------------------------- | ------------------------------------------------- | --------------------------------------------------- | -------------------------------------------- | ----------------------------------------------------------- |
|
|
450
|
+
| Neither meeting nor correlation identifier supplied | Synchronous `Error` from event preparation | Supply call identity before submitting | None; caller bug | `src/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
451
|
+
| Client type or sub-client type unresolved | Synchronous `Error` from origin resolution | Configure the meetings metrics client types | None; configuration bug | `src/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
452
|
+
| Correlation identifier resolves to nothing | Synchronous `Error` from identifier resolution | Supply a correlation identifier | None | `src/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
453
|
+
| Media quality or feature event without meeting identifier | Synchronous `Error` | Only submit these in-meeting | None | `src/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
454
|
+
| Meeting identifier supplied but meeting missing | No throw; failed-to-send client metric recorded | None required | The event is dropped | `src/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
455
|
+
| Batch transport rejects | Rejected promise from the returned submission | Callers through the façade normally ignore it | Network errors re-enqueue with backoff first | `src/call-diagnostic/call-diagnostic-metrics-batcher.ts` |
|
|
456
|
+
|
|
457
|
+
## Pitfalls and constraints
|
|
458
|
+
|
|
459
|
+
- The error classifier order is the behavior. Inserting a classifier changes which code wins for
|
|
460
|
+
errors matching more than one; add a test for the overlap.
|
|
461
|
+
- The Locus 429/503 mapping checks that the raw error's request `uri` (or `url`) contains the literal
|
|
462
|
+
substring `locus`. It does not parse or validate the host, so any URL with `locus` in its path or
|
|
463
|
+
query also matches. Status codes alone are not enough, and a 429 whose URL lacks the substring stays
|
|
464
|
+
unmapped.
|
|
465
|
+
- Event-limit keys are colon-joined with the correlation identifier as the second token;
|
|
466
|
+
`clearEventLimitsForCorrelationId` depends on that layout.
|
|
467
|
+
- Delay mode stores call arguments, not built events, so identity and origin are resolved at flush
|
|
468
|
+
time. Only the trigger time is captured at queue time.
|
|
469
|
+
- `getIdentifiers` defaults the correlation identifier to the string `unknown`, which Call Analyzer's
|
|
470
|
+
UUID validation rejects; the limiter treats `unknown` as unlimited for the same reason.
|
|
471
|
+
- Device details are injected by the device plugin to avoid a circular import; do not import the
|
|
472
|
+
device plugin here.
|
|
473
|
+
|
|
474
|
+
<!-- Include if: the module has conventions beyond repository-wide rules. [condition-id: module.module_specific_conventions] -->
|
|
475
|
+
|
|
476
|
+
## Module-specific rules
|
|
477
|
+
|
|
478
|
+
- Do: add new error mappings to `src/call-diagnostic/config.ts` as code-to-payload entries rather than
|
|
479
|
+
as branches in the classifier.
|
|
480
|
+
- Do: log through the module prefix constants in `src/call-diagnostic/config.ts`.
|
|
481
|
+
- Do: keep media quality events out of empty-key sanitization.
|
|
482
|
+
- Do not: hand-declare event names or payload fields; derive them from `src/metrics.types.ts`.
|
|
483
|
+
- Do not: make event building asynchronous; the unload fetch path depends on it being synchronous.
|
|
484
|
+
|
|
485
|
+
<!-- Include if: the module is published or consumed as a package. [condition-id: module.published_package] -->
|
|
486
|
+
|
|
487
|
+
## Export stability
|
|
488
|
+
|
|
489
|
+
| Export or entry point | Consumer | Stability | Versioning and deprecation rule | Declaration or API report |
|
|
490
|
+
| ------------------------- | ---------------------------------- | --------------------------------- | ------------------------------------------------------------------------------------- | ------------------------- |
|
|
491
|
+
| `CallDiagnosticMetrics` | Meetings plugin, via the façade | Internal plugin export; additive | Public method names are consumed across the monorepo; change with consumers together | `src/index.ts` |
|
|
492
|
+
| `CallDiagnosticLatencies` | Meetings plugin | Internal plugin export; additive | Getter names feed join-time fields; renames are breaking | `src/index.ts` |
|
|
493
|
+
| `CallDiagnosticUtils` | Meetings plugin | Internal plugin export | Helpers re-exported as a namespace | `src/index.ts` |
|
|
494
|
+
| `CALL_DIAGNOSTIC_CONFIG` | Meetings plugin | Internal plugin export | Codes are a wire contract with Call Analyzer | `src/index.ts` |
|
|
495
|
+
|
|
496
|
+
<!-- Include if: the module has a non-obvious design trade-off consumers or maintainers must preserve. [condition-id: module.has_design_tradeoff] -->
|
|
497
|
+
|
|
498
|
+
## Key design trade-off
|
|
499
|
+
|
|
500
|
+
| Chosen trade-off | Preserved invariant or benefit | Cost or limitation | Decision evidence |
|
|
501
|
+
| ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
|
|
502
|
+
| Queue call arguments in delay mode and build at flush time, preserving trigger time | Events raised before identity is known are attributed correctly and keep their real timing | Origin and host state reflect flush time, not trigger time | `src/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
503
|
+
| A fixed-priority error classifier chain ending in an unknown code | Every error yields exactly one deterministic code | Overlapping classifiers silently prefer the earlier one | `src/call-diagnostic/call-diagnostic-metrics.ts` |
|
|
504
|
+
| Attach join times during batch preparation rather than at build time | Latencies use the most complete ledger available at send time | Unload-path events built early may carry incomplete join times | `src/call-diagnostic/call-diagnostic-metrics.util.ts` |
|
|
505
|
+
| Discard skewed Locus sync records instead of reporting them | Sleep and wake clock jumps never pollute sync latency data | Some genuine long syncs are lost | `src/call-diagnostic/call-diagnostic-metrics-latencies.ts` |
|
|
506
|
+
|
|
507
|
+
## Verification
|
|
508
|
+
|
|
509
|
+
| Requirement or invariant | Test level | Positive evidence | Negative or boundary evidence | Gap |
|
|
510
|
+
| ----------------------------- | ---------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------- | ---- |
|
|
511
|
+
| `MOD-001` / `INV-001` | Unit | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none |
|
|
512
|
+
| `MOD-002` | Unit | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none |
|
|
513
|
+
| `MOD-003` | Unit | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none |
|
|
514
|
+
| `MOD-004` / `INV-002` | Unit | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none found | No case asserts an unanonymizable address is dropped |
|
|
515
|
+
| `MOD-005` | Unit | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none |
|
|
516
|
+
| `MOD-006` / `INV-005` | Unit | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts` | none |
|
|
517
|
+
| `MOD-007`, `MOD-008` / `INV-004` | Unit | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none |
|
|
518
|
+
| `MOD-009` | Unit | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none |
|
|
519
|
+
| `MOD-010` / `INV-003` | Unit | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none |
|
|
520
|
+
| `MOD-011` | Unit | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none |
|
|
521
|
+
| `MOD-012` | Unit | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none found | none |
|
|
522
|
+
| `MOD-013` | Unit | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none |
|
|
523
|
+
| `MOD-014` | Unit | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/prelogin-metrics-batcher.ts` | none |
|
|
524
|
+
| `MOD-015` | Unit | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none found | none |
|
|
525
|
+
| `MOD-016` | Unit | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts` | none |
|
|
526
|
+
| `MOD-017` | Unit | `test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts` | none |
|
|
527
|
+
| `MOD-018` / `INV-006` | Unit | `test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts` | none |
|
|
528
|
+
| `MOD-019` / `INV-007` | Unit | `test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts` | none |
|
|
529
|
+
| `MOD-020` | Unit | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts` | none |
|
|
530
|
+
| `MOD-021` | Unit | `test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts` | none found | No case asserts a non-expected code returns false |
|
|
531
|
+
| Batcher success and failure | Unit | `test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts` | `test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts` | none |
|
|
532
|
+
|
|
533
|
+
Record coverage gaps explicitly and link follow-up work. A module specification
|
|
534
|
+
is complete only when its public surface, invariants, failure modes, and test
|
|
535
|
+
evidence agree with the implementation.
|