diff --git a/IMPLEMENTATION_STATUS.md b/IMPLEMENTATION_STATUS.md index 7abef6e..ef329f1 100644 --- a/IMPLEMENTATION_STATUS.md +++ b/IMPLEMENTATION_STATUS.md @@ -4,13 +4,15 @@ ## 当前状态 -### 2026-09-01 主叫实时分析专项整改(执行中) +### 2026-09-01 主叫实时分析专项整改(已完成) - 用户已授权执行专项核对文档中的全部整改,包括代码、数据库迁移、B机发布和受控真实呼叫。 -- 本地已完成:ACK起算的应答证据、显式CLOSE生命周期、生产/采集计数核对、持久缺口与死信、独立Redis、保留维护、查询快照/稳定分页、供应商筛选、告警范围和降级暂停、页面证据字段。 -- 本地验证:ESLint通过,TypeScript构建通过,Prisma schema通过,Vitest 29个文件/118项测试通过,Web生产构建通过;OpenSIPS V2候选配置已在B机执行`opensips -C`通过。 -- 当前阶段:准备提交并发布到B机;发布后的迁移、独立Redis、真实SIP/API/数据库/页面和故障恢复证据将写入`docs/CALLER_REALTIME_ANALYTICS_DELIVERY_20260901.md`。 -- 边界:没有修改计费、余额扣减、路由选择或旧固定6秒CDR逻辑;工作区独立的代码质量审查文件不纳入本次提交。 +- 已完成:ACK起算的应答证据、显式CLOSE生命周期、生产/采集计数核对、持久缺口与死信、独立Redis、保留维护、查询快照/稳定分页、供应商筛选、告警范围和降级暂停、页面证据字段。 +- 本地验证:ESLint、TypeScript构建、Prisma schema、Web生产构建通过;Vitest 29个文件/118项通过;B机OpenSIPS候选配置检查通过。 +- B机已发布提交`9fa1964dec98cbe3c53c901ba764373308054d5e`,发布目录`/opt/lisglosips/releases/caller-analytics-20260901T024406Z`。OpenSIPS、API、CDR Worker、分析Worker、独立Redis及维护timer均为active/enabled,API ready为ok。 +- 真实验收:6通受控SIP得到T=6/C=4/A=2/N=2,两个成功场景完成SDP协商并经过RTPEngine,300ms短通话计A;真实API、MySQL状态/分钟桶、重放幂等、RBAC与页面桌面/移动端均通过。Redis重启恢复、毒事件死信、覆盖降级/恢复、维护与轮转检查通过。证据见`docs/CALLER_REALTIME_ANALYTICS_DELIVERY_20260901.md`及`tests/reports/caller-analytics-real-20260901.json`。 +- 收口:受控测试入口/出口均已禁用,临时UI会话已清零。没有修改计费、余额扣减、路由选择或旧固定6秒CDR逻辑;工作区独立的代码质量审查文件未纳入本次提交。 +- 限制:未取得约定峰值CPS、号码基数和保留期,故不宣称容量上限或统计P95;Git远端HTTP认证失败,B机已部署版本与本地提交存在,但本轮提交未能推送到origin。 ### 2026-08-31 主叫实时分析设计核对与整改方案(仅审查文档) diff --git a/SOFTSWITCH_PLATFORM_DESIGN_V2.md b/SOFTSWITCH_PLATFORM_DESIGN_V2.md index 8e1142d..8ffbb93 100644 --- a/SOFTSWITCH_PLATFORM_DESIGN_V2.md +++ b/SOFTSWITCH_PLATFORM_DESIGN_V2.md @@ -14,7 +14,7 @@ V2 的目标是把当前纯前端原型转化为可部署、可联调、可上 ### 1.1 2026-08-31 新增设计:主叫号码实时分析 -详见 [主叫号码接通率与应答率实时分析设计方案](docs/CALLER_REALTIME_ANALYTICS_DESIGN.md)。该功能处于设计完成、实现待开始阶段。新功能“接通数”按180 Ringing/183 Session Progress或后续阶段统计;“应答数”按实际通话时长大于0统计;实时总体应答率=应答数/总呼叫数,实时已接通应答率=应答数/接通数。直接成功、缺少100、未接通/待接通/未知数据及历史回算边界以专项文档V1.1为准。既有首页历史指标与计费规则不在本次文档任务中变更。 +详见 [主叫号码接通率与应答率实时分析设计方案](docs/CALLER_REALTIME_ANALYTICS_DESIGN.md)。V1.2整改代码、加法迁移及B机测试发布已于2026-09-01完成,真实SIP/API/MySQL/RBAC/UI及可靠性结果见[整改交付报告](docs/CALLER_REALTIME_ANALYTICS_DELIVERY_20260901.md)。新功能“接通数”按180 Ringing/183 Session Progress或后续阶段统计;“应答数”按ACK后可信正通话时长统计;实时总体应答率=应答数/总呼叫数,实时已接通应答率=应答数/接通数。既有首页历史指标、计费规则及旧固定6秒CDR逻辑未变更。当前发布不构成峰值容量或P95承诺。 ## 2. V2 范围 diff --git a/docs/CALLER_REALTIME_ANALYTICS_DELIVERY_20260901.md b/docs/CALLER_REALTIME_ANALYTICS_DELIVERY_20260901.md new file mode 100644 index 0000000..d7da36f --- /dev/null +++ b/docs/CALLER_REALTIME_ANALYTICS_DELIVERY_20260901.md @@ -0,0 +1,64 @@ +# 主叫号码实时分析专项整改交付报告 + +日期:2026-09-01 +状态:整改实现、B机发布及受控功能/可靠性验收完成;容量与真实多线路重试保留明确限制。 + +## 1. 交付版本与边界 + +- B机生效提交:`9fa1964dec98cbe3c53c901ba764373308054d5e`。 +- 发布目录:`/opt/lisglosips/releases/caller-analytics-20260901T024406Z`。 +- 回滚备份:`/var/backups/lisglosips-caller-analytics/20260901T024406Z`。 +- 发布制品SHA-256:`b2f22a04312b1979a11eec62ed797e65ab6c4c8d25174075a8dbc0d723ea7435`。 +- 新采集连续覆盖起点保留为`2026-09-01T02:23:21Z`,发布重启不伪造新的连续历史。 +- 本次只改主叫分析采集、分析存储、API、页面、独立Redis和运维脚本。没有修改计费、余额、路由选择和旧固定6秒CDR逻辑,没有部署A/T,也没有呼叫公网号码。 + +本地标准制品脚本在Windows创建符号链接时遇到`EPERM`。本次使用等价的delta overlay制品:B机先复制上一release,再覆盖本提交受控文件;发布脚本仍执行备份、迁移、候选配置检查、服务切换和健康门槛。 + +## 2. 整改结果 + +| 整改组 | 落地结果 | 状态 | +| --- | --- | --- | +| R01~R03 时长、未知与乱序 | TALK_START在对话路由匹配后产生,ACK后开始计时;时长分未知/暂定/最终;最终零时长具有权威优先级;状态归约支持重复和乱序 | 已完成 | +| R04~R05 完整性、留存与隔离 | 生产/采集计数、水位、日志未读字节、持久gap/DLQ、pending安全裁剪;独立Redis启用AOF、noeviction及256MB上限;维护和logrotate已安装 | 已完成 | +| R06~R07 生命周期与契约 | 增加显式CLOSE、生产节点/boot/sequence、事务阶段、证据来源与算法版本;单attempt保持当前真实路由语义 | 已完成;真实重试启用前补验 | +| R08~R10 API、告警与页面 | 查询覆盖、snapshotId、稳定分页、供应商筛选、未知/null比率、告警规则独立持续计数与降级暂停、详情信令证据均已落地 | 已完成 | +| R11 性能与容量 | 活跃呼叫分页、查询上限、资源隔离和延迟字段已落地;本轮只验证受控功能负载 | 工程整改完成;容量/P95未承诺 | +| R12 发布回滚 | 版本化采集V3、完整备份、逐步回滚、独立Redis备份、配置校验、空闲检查、健康和提交校验已落地并用于本次发布 | 已完成;未逐点实施破坏性失败注入 | +| R13 状态与证据 | V1.2设计、状态索引、测试索引、本报告及机器证据已同步 | 已完成 | + +## 3. 验证结果 + +本地验证全部通过:ESLint、`tsc -b tsconfig.build.json`、Vite生产构建、Prisma schema校验;Vitest共29个文件、118项。OpenSIPS从V1/V2生成V3配置后在B机执行`opensips -C`通过。 + +B机最终审计显示以下服务均为`active/enabled`:OpenSIPS、API、CDR Worker、Caller Analytics Worker、Caller Analytics独立Redis、维护timer。`/api/v2/health/ready`返回`status=ok`,数据库和Redis检查均为ok。独立Redis实测AOF开启、持久化状态正常、`noeviction`、上限256MB;Stream pending为0。 + +末轮6通真实本机回环SIP全部通过原有平台路由,两个成功场景包含SDP offer/answer并通过RTPEngine: + +| 场景 | 统计结果 | +| --- | --- | +| 180后486 | C=1,A=0 | +| 183后487 | C=1,A=0 | +| 直接486 | C=0,A=0 | +| 直接200,ACK后约1.5秒BYE | C=1,A=1 | +| 180→200,ACK后约300ms BYE | C=1,A=1 | +| 100后486 | C=0,A=0 | + +汇总为`T=6、C=4、A=2、N=2`,接通率66.6667%,总体应答率33.3333%,已接通应答率50%,`talkMs=1801`,未知、待接通和暂定应答均为0。实测数据覆盖为`CONTINUOUS`,末次API采集延迟468ms。该单点观测不能替代统计P95。 + +真实API与数据库还验证了状态表/分钟桶逐字段对账、5条事件重放幂等、未认证401、非法查询400、无授权/跨客户403、客户及供应商范围选项不越权。机器证据归档在[caller-analytics-real-20260901.json](../tests/reports/caller-analytics-real-20260901.json)。 + +可靠性验证包括:维护任务dry-run与实际执行、logrotate规则识别、独立Redis重启后Stream长度保持、非法JSON进入持久死信并ACK、覆盖状态转为降级、处置后恢复连续。最终保留一条`RESOLVED`的计划发布重启gap及一条`RESOLVED`的毒事件deadletter,作为审计证据。 + +## 4. 页面验收 + +优先使用Codex Browser插件访问B机时,HTTP入口被客户端阻止,HTTPS尝试超时并重置浏览器内核。按浏览器测试规范改用仓库Playwright和系统Chrome完成回退验收;登录通过真实`/auth/refresh`会话,业务数据来自真实API/MySQL,没有mock、静态替代或localStorage业务数据。 + +已验证应用壳、主叫分析菜单、客户/供应商筛选、连续覆盖、版本/未知字段、三个比例、详情证据及300ms时长,覆盖1440×1000桌面和390×844移动视口。移动端宽表使用现有横向滚动容器,抽屉独立纵向滚动。控制台无错误。截图保存在`.codex-private/caller-analytics-desktop-20260901.png`和`.codex-private/caller-analytics-mobile-20260901.png`。 + +验收后已删除临时登录会话,数据库中对应会话数为0;受控客户入口和供应商出口`cra_20260831`均已恢复为`DISABLED`,测试证据保留。 + +## 5. 未作出的承诺 + +本轮没有可确认的峰值CPS、号码/维度基数和目标保留期,因此没有执行有业务依据的容量压测,也不宣称页面端到端P95≤5秒或机器容量上限。后续在真实多线路重试启用前,还需按实际attemptId和路由策略补做两线路重试验收。上述两项不会把当前单线路统计结果解释成未完成,但限制容量与未来重试能力的对外声明。 + +Git本地提交和B机部署均已完成;`git push origin main`因远端HTTP用户认证失败而未成功。远端仓库在认证恢复前不包含本次提交,不能把B机部署或本地commit表述为已推送。 diff --git a/docs/CALLER_REALTIME_ANALYTICS_DESIGN.md b/docs/CALLER_REALTIME_ANALYTICS_DESIGN.md index af2c553..b149951 100644 --- a/docs/CALLER_REALTIME_ANALYTICS_DESIGN.md +++ b/docs/CALLER_REALTIME_ANALYTICS_DESIGN.md @@ -172,7 +172,7 @@ 新增影响包括OpenSIPS事件采集开销、Redis队列容量、MySQL写放大、查询和缓存负载。统计新表/新服务独立部署并使用功能开关;回滚可关闭采集钩子和分析Worker/入口,保留证据及新表,不删除既有话单、不调整计费余额和路由。生产修改及受控外呼须按届时任务授权执行。 -## 10. 验收用例(设计,尚未执行) +## 10. 验收用例(设计与执行状态) 以下单呼叫终态用例默认T=1;应答时长均指可信实际通话时长。未说明缺口的用例假设完整采集。 @@ -203,7 +203,7 @@ | CRA-023 | 只有可信最终正时长CDR,过程丢失 | 补C/A并标CDR证据,不伪造180/183,不重复T | | CRA-024 | 采集失联导致一个呼叫阶段无法判定 | U单列,T=C+N+U,不自动判失败,率标暂定/不完整 | -功能验收须形成真实SIP信令、API返回、数据库状态/聚合与最终话单的对应证据;mock、静态页面或localStorage不构成功能验收。单元测试用于公式/状态转换,真实联调用于端到端与故障恢复。正常约定负载下事件或可信正时长可用至页面可见的P95目标≤5秒;这是待测目标,不是当前容量承诺。需分别记录采集、消费、API和页面延迟及原有呼叫/计费回归结果。 +功能验收须形成真实SIP信令、API返回、数据库状态/聚合与最终话单的对应证据;mock、静态页面或localStorage不构成功能验收。2026-09-01已完成公式/状态自动化回归、6通受控真实SIP、SDP/RTPEngine、真实API/MySQL/RBAC、重放幂等、故障恢复及真实页面验收,详见[整改交付报告](CALLER_REALTIME_ANALYTICS_DELIVERY_20260901.md)。正常约定负载下事件或可信正时长可用至页面可见的P95目标≤5秒仍为待测目标;当前没有约定峰值负载,不作容量承诺。真实多线路重试在路由功能启用前补验。 ## 11. 本次交付边界 diff --git a/docs/TEST_PLAN_AND_CASES.md b/docs/TEST_PLAN_AND_CASES.md index 223a83b..0c12ebe 100644 --- a/docs/TEST_PLAN_AND_CASES.md +++ b/docs/TEST_PLAN_AND_CASES.md @@ -1977,7 +1977,7 @@ corepack pnpm@10.33.0 exec vitest run apps/worker-recording/src/transfer.spec.ts ## 8A. 主叫号码实时分析验收设计索引(2026-08-31) -[主叫号码实时分析V1.1](CALLER_REALTIME_ANALYTICS_DESIGN.md)第10节定义CRA-001至CRA-024,覆盖180/183业务接通、正时长应答、总体应答率A/T、已接通应答率A/C、直接200/缺少100/零时长/亚秒时长、待接通与未知、线路重试、重复乱序、历史缺口、权限隔离和故障恢复。该组用例目前全部待执行,不计入既有通过数量;最终验收必须有真实SIP、API、数据库及CDR对账证据。 +[主叫号码实时分析V1.2](CALLER_REALTIME_ANALYTICS_DESIGN.md)第10节及第13节定义CRA-001至CRA-034。2026-09-01已完成状态/公式/乱序/告警/查询契约的自动化回归(全量Vitest 29文件/118项),并以6通受控真实SIP完成180、183、直接失败、直接200、ACK后1.5秒/300ms通话、SDP/RTPEngine、真实API、MySQL状态/分钟桶、重放幂等和RBAC验收;Redis重启、毒事件死信、覆盖降级/恢复、维护任务及真实页面也已验证。结果见[整改交付报告](CALLER_REALTIME_ANALYTICS_DELIVERY_20260901.md)和[机器证据JSON](../tests/reports/caller-analytics-real-20260901.json)。未按约定峰值负载执行容量与页面端到端P95统计,因此CRA容量项保持“未执行/不作容量承诺”;真实多线路重试启用前仍须补做对应实际路由验收。 ## 9. 缺陷分级 diff --git a/tests/reports/caller-analytics-real-20260901.json b/tests/reports/caller-analytics-real-20260901.json new file mode 100644 index 0000000..4a9adbf --- /dev/null +++ b/tests/reports/caller-analytics-real-20260901.json @@ -0,0 +1,752 @@ +{ + "date": "2026-09-01T02:44:55.304Z", + "from": "2026-09-01T02:44:48.013Z", + "api": { + "status": 200, + "body": { + "metricVersion": "caller-analytics-v1.1", + "analysisRevision": "caller-analytics-r2", + "snapshotId": "11b2aac60d66a436654584f578321207b4f3c0195942b10630ebd7bba8ed39f6", + "view": "landing", + "from": "2026-09-01T02:44:48.013Z", + "to": "2026-09-01T02:44:55.140Z", + "asOf": "2026-09-01T02:44:55.150Z", + "qualityStatus": "LIVE", + "coverageStatus": "CONTINUOUS", + "dataThrough": "2026-09-01T02:44:53.599Z", + "lagMs": 468, + "durationPrecision": "milliseconds", + "health": { + "gap": false, + "lagMs": 468, + "bootId": "66823a5b-4361-4c39-8bf8-f8db9736347f", + "reason": "", + "degraded": false, + "updatedAt": "2026-09-01T02:44:54.959Z", + "dataThrough": "2026-09-01T02:44:53.599Z", + "spoolOffset": 109742, + "captureSince": "2026-09-01T02:23:21Z", + "coverageStatus": "CONTINUOUS", + "spoolUnreadBytes": 0, + "producerEventCount": 32, + "collectedEventCount": 32 + }, + "gaps": [], + "summary": { + "totalCalls": 6, + "connectedCalls": 4, + "answeredCalls": 2, + "failedCalls": 2, + "pendingCalls": 0, + "unknownCalls": 0, + "activeCalls": 0, + "talkMs": 1801, + "durationUnknownCalls": 0, + "provisionalAnsweredCalls": 0, + "notConnectedCalls": 2, + "connectionRate": 66.6667, + "overallAnswerRate": 33.3333, + "connectedAnswerRate": 50 + }, + "summaryScope": "时间及业务筛选;样本/比例/异常筛选仅影响号码列表", + "numbers": [ + { + "customerId": "cra_20260831", + "caller": "99100001", + "totalCalls": 6, + "connectedCalls": 4, + "answeredCalls": 2, + "failedCalls": 2, + "pendingCalls": 0, + "unknownCalls": 0, + "activeCalls": 0, + "talkMs": 1801, + "durationUnknownCalls": 0, + "provisionalAnsweredCalls": 0, + "notConnectedCalls": 2, + "connectionRate": 66.6667, + "overallAnswerRate": 33.3333, + "connectedAnswerRate": 50, + "alert": null + } + ], + "total": 1, + "skip": 0, + "take": 25, + "trends": [ + { + "time": 1788230640000, + "totalCalls": 6, + "connectedCalls": 4, + "answeredCalls": 2, + "failedCalls": 2, + "pendingCalls": 0, + "unknownCalls": 0, + "activeCalls": 0, + "talkMs": 1801, + "durationUnknownCalls": 0, + "provisionalAnsweredCalls": 0, + "caller": "", + "customerId": "", + "notConnectedCalls": 2, + "connectionRate": 66.6667, + "overallAnswerRate": 33.3333, + "connectedAnswerRate": 50 + } + ], + "baseFilters": { + "view": "landing", + "from": "2026-09-01T02:44:48.013Z", + "to": "2026-09-01T02:44:55.140Z", + "customerId": "cra_20260831", + "customerGatewayId": "", + "vendorId": "", + "vendorGatewayId": "", + "caller": "", + "city": "", + "carrier": "" + }, + "numberFilters": { + "minSamples": 0, + "onlyAlerts": false, + "connectionMin": 0, + "connectionMax": 100, + "overallMin": 0, + "overallMax": 100, + "connectedMin": 0, + "connectedMax": 100 + }, + "metricAvailability": { + "connectionRate": true, + "answerRates": true + }, + "historyNotice": "当前窗口在连续采集覆盖内;旧固定6秒话单不参与校准。" + } + }, + "detail": { + "rows": [ + { + "id": "bd2f99d0f2f094dafa116dc400cfb9d7d8371005cc529737e327dfeb1d9b8345", + "callKey": "be549d085a7dee62f13ae303c379803081d7bc8e5436e80fed9a933707c22d0d", + "startedAt": "2026-09-01T02:44:52.099Z", + "caller": "99100001", + "callee": "99106", + "vendorGatewayId": "cra_20260831", + "counts": { + "talkMs": 0, + "totalCalls": 1, + "activeCalls": 0, + "failedCalls": 1, + "pendingCalls": 0, + "unknownCalls": 0, + "answeredCalls": 0, + "connectedCalls": 0, + "durationUnknownCalls": 0, + "provisionalAnsweredCalls": 0 + }, + "payload": { + "event": { + "at": 1788230692099, + "city": "UNKNOWN", + "code": 0, + "cseq": "", + "kind": "ATTEMPT", + "bootId": "66823a5b-4361-4c39-8bf8-f8db9736347f", + "branch": "", + "callId": "cra-99106-d9a7fdb7122b429b8eb2925d6ee8df7d@loopback", + "callee": "99106", + "caller": "99100001", + "method": "INVITE", + "nodeId": "YanZi", + "source": "opensips", + "talkMs": null, + "callUid": "e8c57831b2aac971c4ca3583cb67cad8582eed13b58e7ea39f5f0be2bc86c6ed", + "carrier": "UNKNOWN", + "eventId": "231e79d6950e2d7307bfe838c6baf2ca4d3ecc9c83bd929e6b3045bd2139021c", + "sequence": 1788230692099000, + "vendorId": "cra_20260831", + "attemptId": "1", + "startedAt": 1788230692099, + "customerId": "cra_20260831", + "receivedAt": 1788230692439, + "landingCaller": "99100001", + "schemaVersion": 2, + "evidenceVersion": 2, + "vendorGatewayId": "cra_20260831", + "customerGatewayId": "cra_20260831" + }, + "talkMs": 0, + "endedAt": 1788230693599, + "unknown": false, + "finalCode": 486, + "acceptedAt": null, + "durationAt": 1788230693599, + "first180At": null, + "first183At": null, + "durationFinal": true, + "talkStartedAt": null, + "durationComplete": true, + "durationAuthority": 1, + "terminationReason": "verified-dialog-final" + } + }, + { + "id": "1ced517eabcf44a9c87bbb01859b0478486e3de0c57c9aacbc88373b26caa332", + "callKey": "87a0252e111310be93d0ac6200ca31519408e7eda0f6d0019e58129dbb394c8e", + "startedAt": "2026-09-01T02:44:51.345Z", + "caller": "99100001", + "callee": "99105", + "vendorGatewayId": "cra_20260831", + "counts": { + "talkMs": 300, + "totalCalls": 1, + "activeCalls": 0, + "failedCalls": 0, + "pendingCalls": 0, + "unknownCalls": 0, + "answeredCalls": 1, + "connectedCalls": 1, + "durationUnknownCalls": 0, + "provisionalAnsweredCalls": 0 + }, + "payload": { + "event": { + "at": 1788230691346, + "city": "UNKNOWN", + "code": 0, + "cseq": "", + "kind": "ATTEMPT", + "bootId": "66823a5b-4361-4c39-8bf8-f8db9736347f", + "branch": "", + "callId": "cra-99105-f2cc27a5f1c44e3097a1ba39497600a1@loopback", + "callee": "99105", + "caller": "99100001", + "method": "INVITE", + "nodeId": "YanZi", + "source": "opensips", + "talkMs": null, + "callUid": "158db5741881d9555396f88f8d71be8114b3de9b3fbb01b1977afc3216c191f3", + "carrier": "UNKNOWN", + "eventId": "a2573b627de297d67e9800ad9ce123999e4a56885c9fe4b60f8e046df0072622", + "sequence": 1788230691346000, + "vendorId": "cra_20260831", + "attemptId": "1", + "startedAt": 1788230691345, + "customerId": "cra_20260831", + "receivedAt": 1788230691655, + "landingCaller": "99100001", + "schemaVersion": 2, + "evidenceVersion": 2, + "vendorGatewayId": "cra_20260831", + "customerGatewayId": "cra_20260831" + }, + "talkMs": 300, + "endedAt": 1788230691797, + "unknown": false, + "finalCode": 200, + "acceptedAt": 1788230691496, + "durationAt": 1788230691797, + "first180At": 1788230691346, + "first183At": null, + "durationFinal": true, + "talkStartedAt": 1788230691497, + "durationComplete": true, + "durationAuthority": 1, + "terminationReason": "verified-dialog-final" + } + }, + { + "id": "4c4589bdcd2ef482d577a76f47e7e3cd504bd05aee95b6228a86939e89530940", + "callKey": "52584c11a53a7388dd68ad49afc1e5dfc407b851aa12a813229eb81265975f71", + "startedAt": "2026-09-01T02:44:49.540Z", + "caller": "99100001", + "callee": "99104", + "vendorGatewayId": "cra_20260831", + "counts": { + "talkMs": 1501, + "totalCalls": 1, + "activeCalls": 0, + "failedCalls": 0, + "pendingCalls": 0, + "unknownCalls": 0, + "answeredCalls": 1, + "connectedCalls": 1, + "durationUnknownCalls": 0, + "provisionalAnsweredCalls": 0 + }, + "payload": { + "event": { + "at": 1788230689541, + "city": "UNKNOWN", + "code": 0, + "cseq": "", + "kind": "ATTEMPT", + "bootId": "66823a5b-4361-4c39-8bf8-f8db9736347f", + "branch": "", + "callId": "cra-99104-95c6b3c023b94f4f9fdd7781c37587f8@loopback", + "callee": "99104", + "caller": "99100001", + "method": "INVITE", + "nodeId": "YanZi", + "source": "opensips", + "talkMs": null, + "callUid": "5c68fe746adb05173b06bbc7f1fc3fb60b15a2c155500be4d5c860a34fcd408d", + "carrier": "UNKNOWN", + "eventId": "1b15c22588b24db034cff9e4a7bfa135d326ba3b38c8f592952fb72aaf13c041", + "sequence": 1788230689541000, + "vendorId": "cra_20260831", + "attemptId": "1", + "startedAt": 1788230689540, + "customerId": "cra_20260831", + "receivedAt": 1788230689889, + "landingCaller": "99100001", + "schemaVersion": 2, + "evidenceVersion": 2, + "vendorGatewayId": "cra_20260831", + "customerGatewayId": "cra_20260831" + }, + "talkMs": 1501, + "endedAt": 1788230691043, + "unknown": false, + "finalCode": 200, + "acceptedAt": 1788230689541, + "durationAt": 1788230691043, + "first180At": null, + "first183At": null, + "durationFinal": true, + "talkStartedAt": 1788230689542, + "durationComplete": true, + "durationAuthority": 1, + "terminationReason": "verified-dialog-final" + } + }, + { + "id": "cdcbfca07604ebff4bbe4fe6734873f0eea61d1f798825b0ff2e698e33d0d6e6", + "callKey": "7a108c8adcfc4af723c08103a2be7bba190f9d42a6b8edc272cc2542a5fe6330", + "startedAt": "2026-09-01T02:44:49.239Z", + "caller": "99100001", + "callee": "99103", + "vendorGatewayId": "cra_20260831", + "counts": { + "talkMs": 0, + "totalCalls": 1, + "activeCalls": 0, + "failedCalls": 1, + "pendingCalls": 0, + "unknownCalls": 0, + "answeredCalls": 0, + "connectedCalls": 0, + "durationUnknownCalls": 0, + "provisionalAnsweredCalls": 0 + }, + "payload": { + "event": { + "at": 1788230689239, + "city": "UNKNOWN", + "code": 0, + "cseq": "", + "kind": "ATTEMPT", + "bootId": "66823a5b-4361-4c39-8bf8-f8db9736347f", + "branch": "", + "callId": "cra-99103-53e5a373297a43919927eebd528cd362@loopback", + "callee": "99103", + "caller": "99100001", + "method": "INVITE", + "nodeId": "YanZi", + "source": "opensips", + "talkMs": null, + "callUid": "cd37b5bfc20e65e02019970b922add6fab0e8980d6620fb4edadbde91428dc47", + "carrier": "UNKNOWN", + "eventId": "60c7fa2f2798a67e603bb6d4a39daa3bdc402ca3d3a924611e1067692372dba3", + "sequence": 1788230689239000, + "vendorId": "cra_20260831", + "attemptId": "1", + "startedAt": 1788230689239, + "customerId": "cra_20260831", + "receivedAt": 1788230689889, + "landingCaller": "99100001", + "schemaVersion": 2, + "evidenceVersion": 2, + "vendorGatewayId": "cra_20260831", + "customerGatewayId": "cra_20260831" + }, + "talkMs": 0, + "endedAt": 1788230689239, + "unknown": false, + "finalCode": 486, + "acceptedAt": null, + "durationAt": 1788230689239, + "first180At": null, + "first183At": null, + "durationFinal": true, + "talkStartedAt": null, + "durationComplete": true, + "durationAuthority": 1, + "terminationReason": "verified-dialog-final" + } + }, + { + "id": "662cc9075f141345c45a274d2412d4ebffdf043dd75fa1b6e1a6ac9d85ce9460", + "callKey": "6c05dd76e643c25294847a1163d623262108b4176e37e33b51fc3685355f19f9", + "startedAt": "2026-09-01T02:44:48.787Z", + "caller": "99100001", + "callee": "99102", + "vendorGatewayId": "cra_20260831", + "counts": { + "talkMs": 0, + "totalCalls": 1, + "activeCalls": 0, + "failedCalls": 0, + "pendingCalls": 0, + "unknownCalls": 0, + "answeredCalls": 0, + "connectedCalls": 1, + "durationUnknownCalls": 0, + "provisionalAnsweredCalls": 0 + }, + "payload": { + "event": { + "at": 1788230688787, + "city": "UNKNOWN", + "code": 0, + "cseq": "", + "kind": "ATTEMPT", + "bootId": "66823a5b-4361-4c39-8bf8-f8db9736347f", + "branch": "", + "callId": "cra-99102-5b8fad37fb9141d6ba5e5453e8372d4a@loopback", + "callee": "99102", + "caller": "99100001", + "method": "INVITE", + "nodeId": "YanZi", + "source": "opensips", + "talkMs": null, + "callUid": "7cda6788fb05dd8dcf36a3c2ffbb8fe124c9746a2c32bca294954ef72c91c748", + "carrier": "UNKNOWN", + "eventId": "17d7dc0a0bb67acb249cb5a1f82615e513853127cd327818224c492fa0dc16a3", + "sequence": 1788230688787000, + "vendorId": "cra_20260831", + "attemptId": "1", + "startedAt": 1788230688787, + "customerId": "cra_20260831", + "receivedAt": 1788230689112, + "landingCaller": "99100001", + "schemaVersion": 2, + "evidenceVersion": 2, + "vendorGatewayId": "cra_20260831", + "customerGatewayId": "cra_20260831" + }, + "talkMs": 0, + "endedAt": 1788230688938, + "unknown": false, + "finalCode": 487, + "acceptedAt": null, + "durationAt": 1788230688938, + "first180At": null, + "first183At": 1788230688787, + "durationFinal": true, + "talkStartedAt": null, + "durationComplete": true, + "durationAuthority": 1, + "terminationReason": "verified-dialog-final" + } + }, + { + "id": "f5a3e11aa1b23e91559582bf2ea0dbc32032c0b5bb55a04d28f1ab02bbb5a64b", + "callKey": "fe25de2674a793555634a0b1732790425667f16cc81f89a3e28aaa46e35c3acc", + "startedAt": "2026-09-01T02:44:48.335Z", + "caller": "99100001", + "callee": "99101", + "vendorGatewayId": "cra_20260831", + "counts": { + "talkMs": 0, + "totalCalls": 1, + "activeCalls": 0, + "failedCalls": 0, + "pendingCalls": 0, + "unknownCalls": 0, + "answeredCalls": 0, + "connectedCalls": 1, + "durationUnknownCalls": 0, + "provisionalAnsweredCalls": 0 + }, + "payload": { + "event": { + "at": 1788230688335, + "city": "UNKNOWN", + "code": 0, + "cseq": "", + "kind": "ATTEMPT", + "bootId": "66823a5b-4361-4c39-8bf8-f8db9736347f", + "branch": "", + "callId": "cra-99101-7c962c8b0e6f4dc6aa922e850c96cbbe@loopback", + "callee": "99101", + "caller": "99100001", + "method": "INVITE", + "nodeId": "YanZi", + "source": "opensips", + "talkMs": null, + "callUid": "69136797dbe483cbd977dcf5576464b07eda7fe03ca8d7810144b9de44b99423", + "carrier": "UNKNOWN", + "eventId": "d4b0b273a78d6aad97e695882c34a44c59fc8a9c1130b98c5865b4b00f8cadb1", + "sequence": 1788230688335000, + "vendorId": "cra_20260831", + "attemptId": "1", + "startedAt": 1788230688335, + "customerId": "cra_20260831", + "receivedAt": 1788230688370, + "landingCaller": "99100001", + "schemaVersion": 2, + "evidenceVersion": 2, + "vendorGatewayId": "cra_20260831", + "customerGatewayId": "cra_20260831" + }, + "talkMs": 0, + "endedAt": 1788230688486, + "unknown": false, + "finalCode": 486, + "acceptedAt": null, + "durationAt": 1788230688486, + "first180At": 1788230688336, + "first183At": null, + "durationFinal": true, + "talkStartedAt": null, + "durationComplete": true, + "durationAuthority": 1, + "terminationReason": "verified-dialog-final" + } + } + ], + "breakdown": [ + { + "vendorGatewayId": "cra_20260831", + "city": "UNKNOWN", + "carrier": "UNKNOWN", + "totalCalls": 6, + "connectedCalls": 4, + "answeredCalls": 2, + "failedCalls": 2, + "pendingCalls": 0, + "unknownCalls": 0, + "activeCalls": 0, + "talkMs": 1801, + "durationUnknownCalls": 0, + "provisionalAnsweredCalls": 0, + "caller": "", + "customerId": "", + "notConnectedCalls": 2, + "connectionRate": 66.6667, + "overallAnswerRate": 33.3333, + "connectedAnswerRate": 50 + } + ], + "breakdownTruncated": false, + "skip": 0, + "take": 25 + }, + "sip": [ + { + "callId": "cra-99101-7c962c8b0e6f4dc6aa922e850c96cbbe@loopback", + "direction": "UAC", + "code": 100, + "sdp": false, + "time": 1788230688.3355267 + }, + { + "callId": "cra-99101-7c962c8b0e6f4dc6aa922e850c96cbbe@loopback", + "direction": "UAS", + "code": 180, + "sdp": false, + "time": 1788230688.3360817 + }, + { + "callId": "cra-99101-7c962c8b0e6f4dc6aa922e850c96cbbe@loopback", + "direction": "UAC", + "code": 180, + "sdp": false, + "time": 1788230688.3362823 + }, + { + "callId": "cra-99101-7c962c8b0e6f4dc6aa922e850c96cbbe@loopback", + "direction": "UAS", + "code": 486, + "sdp": false, + "time": 1788230688.4863043 + }, + { + "callId": "cra-99101-7c962c8b0e6f4dc6aa922e850c96cbbe@loopback", + "direction": "UAC", + "code": 486, + "sdp": false, + "time": 1788230688.4864848 + }, + { + "callId": "cra-99102-5b8fad37fb9141d6ba5e5453e8372d4a@loopback", + "direction": "UAC", + "code": 100, + "sdp": false, + "time": 1788230688.7877743 + }, + { + "callId": "cra-99102-5b8fad37fb9141d6ba5e5453e8372d4a@loopback", + "direction": "UAS", + "code": 183, + "sdp": false, + "time": 1788230688.7879457 + }, + { + "callId": "cra-99102-5b8fad37fb9141d6ba5e5453e8372d4a@loopback", + "direction": "UAC", + "code": 183, + "sdp": false, + "time": 1788230688.7880127 + }, + { + "callId": "cra-99102-5b8fad37fb9141d6ba5e5453e8372d4a@loopback", + "direction": "UAS", + "code": 487, + "sdp": false, + "time": 1788230688.9381335 + }, + { + "callId": "cra-99102-5b8fad37fb9141d6ba5e5453e8372d4a@loopback", + "direction": "UAC", + "code": 487, + "sdp": false, + "time": 1788230688.9384828 + }, + { + "callId": "cra-99103-53e5a373297a43919927eebd528cd362@loopback", + "direction": "UAC", + "code": 100, + "sdp": false, + "time": 1788230689.239587 + }, + { + "callId": "cra-99103-53e5a373297a43919927eebd528cd362@loopback", + "direction": "UAS", + "code": 486, + "sdp": false, + "time": 1788230689.2397466 + }, + { + "callId": "cra-99103-53e5a373297a43919927eebd528cd362@loopback", + "direction": "UAC", + "code": 486, + "sdp": false, + "time": 1788230689.2398334 + }, + { + "callId": "cra-99104-95c6b3c023b94f4f9fdd7781c37587f8@loopback", + "direction": "UAC", + "code": 100, + "sdp": false, + "time": 1788230689.541705 + }, + { + "callId": "cra-99104-95c6b3c023b94f4f9fdd7781c37587f8@loopback", + "direction": "UAS", + "code": 200, + "sdp": true, + "time": 1788230689.5418484 + }, + { + "callId": "cra-99104-95c6b3c023b94f4f9fdd7781c37587f8@loopback", + "direction": "UAC", + "code": 200, + "sdp": true, + "time": 1788230689.54246 + }, + { + "callId": "cra-99105-f2cc27a5f1c44e3097a1ba39497600a1@loopback", + "direction": "UAC", + "code": 100, + "sdp": false, + "time": 1788230691.3461745 + }, + { + "callId": "cra-99105-f2cc27a5f1c44e3097a1ba39497600a1@loopback", + "direction": "UAS", + "code": 180, + "sdp": false, + "time": 1788230691.3463302 + }, + { + "callId": "cra-99105-f2cc27a5f1c44e3097a1ba39497600a1@loopback", + "direction": "UAC", + "code": 180, + "sdp": false, + "time": 1788230691.3463998 + }, + { + "callId": "cra-99105-f2cc27a5f1c44e3097a1ba39497600a1@loopback", + "direction": "UAS", + "code": 200, + "sdp": true, + "time": 1788230691.4965453 + }, + { + "callId": "cra-99105-f2cc27a5f1c44e3097a1ba39497600a1@loopback", + "direction": "UAC", + "code": 200, + "sdp": true, + "time": 1788230691.4974086 + }, + { + "callId": "cra-99106-d9a7fdb7122b429b8eb2925d6ee8df7d@loopback", + "direction": "UAC", + "code": 100, + "sdp": false, + "time": 1788230692.099361 + }, + { + "callId": "cra-99106-d9a7fdb7122b429b8eb2925d6ee8df7d@loopback", + "direction": "UAS", + "code": 100, + "sdp": false, + "time": 1788230692.0994966 + }, + { + "callId": "cra-99106-d9a7fdb7122b429b8eb2925d6ee8df7d@loopback", + "direction": "UAS", + "code": 486, + "sdp": false, + "time": 1788230693.5997336 + }, + { + "callId": "cra-99106-d9a7fdb7122b429b8eb2925d6ee8df7d@loopback", + "direction": "UAC", + "code": 486, + "sdp": false, + "time": 1788230693.5999396 + } + ], + "bucketAudit": { + "totalCalls": 54, + "connectedCalls": 36, + "answeredCalls": 16, + "failedCalls": 18, + "pendingCalls": 0, + "unknownCalls": 0, + "activeCalls": 0, + "talkMs": 14405, + "durationUnknownCalls": 2, + "provisionalAnsweredCalls": 0, + "notConnectedCalls": 18, + "connectionRate": null, + "overallAnswerRate": null, + "connectedAnswerRate": null + }, + "replayed": 5, + "tests": [ + "real SIP six scenarios", + "two SDP offer/answer negotiations through RTPEngine", + "ACK-based positive duration including subsecond call", + "real API counts, completeness and three rates", + "real DB states and minute buckets", + "database replay idempotency", + "customer scope and 403 isolation", + "scoped customer/vendor filter options", + "unauthenticated 401", + "invalid query 400" + ] +} \ No newline at end of file