This commit is contained in:
@@ -0,0 +1,211 @@
|
||||
# CMPP 协议字段兼容性整改方案
|
||||
|
||||
日期:2026-09-20。状态:六类整改已在 `b24cd7c` 基线上实施并完成本地定向验收;目标环境未迁移、未发布。实施证据及剩余边界见第 10 节。
|
||||
|
||||
## 1. 目标、范围与授权
|
||||
|
||||
解决平台内部字段容量和编解码规则小于 CMPP 协议允许范围的问题,避免合法回执、上行和提交结果被拒绝,或被错误解释。
|
||||
|
||||
本方案覆盖 CMPP 2.0/3.0 的 Gateway 编解码、Redis/HTTP 事件、后端参数、Prisma、PostgreSQL 和下游投递。初稿授权仅为文档审查;后续用户明确授权基于最新代码执行方案、修复并本地提交。实施范围为本地代码、隔离基础设施验证和文档,不包含推送、环境发布、预生产迁移、再次重投或业务配置变更。应急恢复独立记录,不作为本方案验收结果。
|
||||
|
||||
本方案是 [发送链路设计](phase-4-send-pipeline-redesign.md) 的字段兼容性补充,不替代其发送尝试归属、终态、补发、事务和账务设计;不替代 [计费方案](phase-5-billing-plan.md)、[测试计划](testing-plan.md) 和 [部署手册](production-deployment.md)。协议兼容整改不改变客户费率、路由、补发策略或退款规则。
|
||||
|
||||
实施前复读 [需求](first-version-development-requirements.md)、[系统测试用例](system-functional-test-cases.md)、[测试进度](testing-progress.md) 与当前代码;将本文新增用例纳入既有测试体系,避免形成两套验收标准。
|
||||
|
||||
## 2. 初稿审查基线与证据边界(历史记录)
|
||||
|
||||
- 本地审查基线:main / `c20c224`;存在大量其他会话未提交修改,不能将工作区整体作为本方案可提交内容。上述提交包含的长短信终态修复与本方案不是同一变更。
|
||||
- 预生产只读核验:2026-09-20 14:56:46(北京时间),应用标记为 `1676cfe622f648bbfe09ac027e3db91737a7789d`。通过 `information_schema.columns` 核对实际字段类型,并核对部署目录源码/后端产物中的相关实现。该记录不是以后发布时可复用的现场结论,也不是对运行 Gateway 二进制逐项反编译验证。
|
||||
- 已知线上故障:上游回执头序号 `2245918284`、`2245918288` 超过 PostgreSQL integer 上限,原业务回执入库受阻。完整应急恢复清单、处理结果和副作用由主任务独立记录,本方案不宣称恢复已完成。
|
||||
- 其余发现来自协议原文、静态调用路径和内存边界核算;尚未用真实 TCP、真实后端和隔离 PostgreSQL 完成回归,不能写成线上已经发生同类故障。
|
||||
- 本次未修改代码、数据库、Redis、业务配置或服务,未发送测试报文。
|
||||
|
||||
协议依据为中国移动规范原文的公开镜像:
|
||||
|
||||
1. [CMPP 2.0](https://www.kannel.org/~tolj/specs/CMPP2/CMPP-2.0.pdf):第 7.3 节消息头及 SP/ISMG 消息定义。
|
||||
2. [CMPP 3.0](https://www.kannel.org/~tolj/specs/CMPP2/CMPP-v30.pdf):第 8.3 节消息头、第 8.4.1.2 节连接响应、第 8.4.3 节 Submit、第 8.4.5 节 Deliver/状态报告及 Deliver 响应。
|
||||
|
||||
协议中的字段字节数还须结合语义限制解释,不能把字段可表示范围当作所有业务值都有效。例如 Msg_Length 虽占 1 字节,仍受对应编码的内容长度规定约束。
|
||||
|
||||
## 3. 问题清单
|
||||
|
||||
| 编号 | 优先级 | 问题及证据 | 后果与当前确认程度 |
|
||||
|---|---|---|---|
|
||||
| CMPP-FIELD-01 | P1,首批必修 | 5 个 sequenceId 字段为有符号 integer;协议为 4 字节无符号整数 | 已发生回执入库故障;其他字段同类风险已确认,尚未逐条实测 |
|
||||
| CMPP-FIELD-02 | P2 | 两张下游表的 ackResult 为 integer;CMPP 3.0 DELIVER_RESP.Result 为 4 字节无符号整数,9 及以上可表示其他错误 | 大错误码可能入库失败,常见 0~9 不触发此容量问题;未确认线上命中 |
|
||||
| CMPP-FIELD-03 | P1 | 2.0/3.0 共用固定 60 字节状态报告编解码,号码字段固定 21 字节 | 3.0 应为 32 字节号码字段、71 字节报告体;可能错读 SMSC_sequence,发出不符合 3.0 格式的报告 |
|
||||
| CMPP-FIELD-04 | P1 | 下游目标选择过滤 sequenceId <= 0,Gateway 用 0 表示缺失 | 0 可由无符号字段表示,已核对章节未将其保留;合法 0 序号无法正确生成或恢复通知 |
|
||||
| CMPP-FIELD-05 | P1 | 3.0 CONNECT_RESP.Status 从 uint32 强转 uint8 | 256 会截为 0,客户端误判认证成功;这是本地状态误判,不代表上游真的授予权限 |
|
||||
| CMPP-FIELD-06 | P2 | CMPP3_PACKET_MAX 固定 3335 | 合法的 99 个收件人、140 字节内容的 Submit 总长 3471,会在解码前被拒绝 |
|
||||
|
||||
### 3.1 数据库字段逐项清单
|
||||
|
||||
协议 uint32 表示范围为 `0..4294967295`,现有 integer 为 `-2147483648..2147483647`。
|
||||
|
||||
| 表 | 字段 | 当前实际类型 | 对应业务 |
|
||||
|---|---|---|---|
|
||||
| UpstreamReceiptInbox | sequenceId | integer,可空 | 上游回执接收 |
|
||||
| SmsReceiptRecord | sequenceId | integer,可空 | 业务回执记录 |
|
||||
| SmsUplinkMessage | sequenceId | integer,可空 | 上行短信 |
|
||||
| SmsSubmitRecord | sequenceId | integer,可空 | 向上游提交结果 |
|
||||
| SmsMessageSegmentAudit | sequenceId | integer,可空 | 长短信分片提交/回执审计 |
|
||||
| CmppDownstreamDelivery | ackResult | integer,可空 | 下游确认结果 |
|
||||
| CmppDownstreamDeliveryAttempt | ackResult | integer,可空 | 每次下游投递确认结果 |
|
||||
|
||||
代码入口:[schema.prisma](../api/prisma/schema.prisma)、[回执处理](../api/src/send-chain/send-receipt.service.ts)、[提交结果](../api/src/send-chain/send-gateway-result.service.ts)、[上行处理](../api/src/send-chain/send-downstream-delivery.service.ts)、[下游状态](../api/src/send-chain/send-downstream-state.service.ts)。不得只修改收件箱,否则后续落库仍可能失败。
|
||||
|
||||
### 3.2 协议与调用路径证据
|
||||
|
||||
- [Gateway 事件结构](../gateway/internal/queue/messages.go) 的 SequenceID 已是 uint32;Msg_Id 转为十进制字符串进入事件,序号超限发生在后端持久化边界。
|
||||
- [receipt.go](../gateway/third_party/gocmpp/receipt.go) 的 CmppReceiptPktLen=60,Pack/Unpack 均使用 21 字节号码。[上游处理](../gateway/internal/upstream/deliver.go) 对 2.0/3.0 共用此解析器;[下游投递](../gateway/internal/inbound/delivery.go) 共用此打包器。
|
||||
- [下游目标选择](../api/src/send-chain/downstream-receipt-targets.ts) 过滤 <=0;[下游投递](../gateway/internal/inbound/delivery.go) 使用 ==0/!=0 判定是否提供原 Submit 序号。
|
||||
- [client.go](../gateway/third_party/gocmpp/client.go) 执行 `status = uint8(rsp.Status)` 后按是否为 0 判断成功;[上游连接](../gateway/internal/upstream/connection.go) 实际调用该客户端。
|
||||
- [packet.go](../gateway/third_party/gocmpp/packet.go) 设置 3335 上限;[conn.go](../gateway/third_party/gocmpp/conn.go) 在收包时执行;[submit.go](../gateway/third_party/gocmpp/submit.go) 的 3.0 长度公式为 `12 + 129 + 32*N + 1 + 1 + MsgLength + 20`。N=99、MsgLength=140 得到 3471,且 99 满足规范“小于100”。
|
||||
|
||||
内存核算还确认:正确 71 字节回执中 SMSC_sequence 的起始偏移为 67;旧代码从偏移 56 读取。对普通 11 位号码,号码可能仍正确,但后续序号会读到补零。不能以手机号看起来正常证明整个报文正确。
|
||||
|
||||
## 4. 目标设计
|
||||
|
||||
### 4.1 uint32 存储和接口边界
|
||||
|
||||
建议统一采用:Gateway uint32 → JSON number → 后端校验后的 number → 持久化适配器 BigInt → Prisma BigInt / PostgreSQL bigint。
|
||||
|
||||
- 上述 7 字段统一升级;保留可空属性,已有 NULL 表示历史未采集,不转换成 0。
|
||||
- 非空合法范围为 0~4294967295;拒绝负数、小数、NaN、无穷大和超上限值。必填协议头字段不应因内部接口可空而被静默省略。
|
||||
- number 精确覆盖全部 uint32;进入 ORM 时显式转换为 BigInt,读取后检查范围再转 number,保持现有事件/API 的数值契约,避免把 Prisma BigInt 直接送入 JSON。
|
||||
- 使用字段专用转换函数,覆盖查询条件、create/update/upsert、原始 SQL、批量查询、DTO、队列回放、审计、报表和导出。不能靠修改全局 BigInt.toJSON 掩盖边界。
|
||||
- 数据库增加非空值范围约束。旧负值先列入异常清单,不擅自加 2^32“纠正”;须有原始报文佐证并单独处理。
|
||||
- API、Worker、Callback 等所有读取这些字段的进程必须一起完成兼容验证。协议字段升级不得污染既有金额 BigInt 的单位和序列化规则。
|
||||
|
||||
`Msg_Id` 不套用上述方案:它是 uint64,完整上限为 18446744073709551615,超出 JavaScript 安全整数及 PostgreSQL 有符号 bigint。继续使用 Gateway uint64、跨服务十进制字符串和数据库 text;必要时校验十进制格式及 uint64 上限,不使用 Number/parseInt 中转。
|
||||
|
||||
### 4.2 CMPP 2.0/3.0 状态报告编解码
|
||||
|
||||
- 显式区分协议版本:2.0 的号码字段 21 字节、报告体 60 字节;3.0 分别为 32、71 字节。
|
||||
- 收包按协商版本与报告体实际长度校验后解析;发送按下游连接协商版本打包。同步更新协议日志解析路径,避免业务解析正确但日志仍错位。
|
||||
- 严格校验截断、额外字节、填充和字段边界;不能仅更改总长度常量,必须同时更改字段偏移与读写长度。
|
||||
- 某些供应商可能在 3.0 连接上发送 60 字节历史格式。先盘点脱敏报文;如确有兼容需求,设计显式、可审计的兼容策略并测试,不凭长度默默切换,也不强制修改通道配置。本方案不默认启用降级。
|
||||
- 不新增 SMSC_sequence、LinkID、供应商时间字段的业务存储需求;它们的原始报文保留和追踪另按既有审计方案执行。暂不落库不等于可以错读字段位置。
|
||||
|
||||
### 4.3 序号 0 与缺失的区别
|
||||
|
||||
- 用 null/undefined 或明确存在标志表示未提供;0 是合法已提供的数值。
|
||||
- Gateway 可用可空 uint32 或等价带存在标志的结构,检查 JSON omitempty、默认值、恢复映射、幂等键和分片目标生成的全部路径。
|
||||
- 不将空字符串经 Number 转换为 0;旧空字符串仍视为缺失。分别测试数字 0、字符串 "0"、空串、null 和未提供字段。
|
||||
- 保留原始客户 Submit 序号及 Msg_Id 对应关系,不生成替代序号。回卷到 0 后,未完成请求不得发生映射碰撞。
|
||||
|
||||
### 4.4 连接响应状态与收包长度
|
||||
|
||||
- 3.0 CONNECT_RESP.Status 全程使用 uint32;2.0 uint8 可无损提升。只有原始值 0 表示成功,未知非零值仍失败,日志保留完整原值。
|
||||
- 根据支持的命令、版本、合法收件人数及内容长度重新计算收包边界;既不能保留过小总上限,也不能取消上限或直接接受任意长度。
|
||||
- 检查长度公式、实际编码长度、读缓冲区和内存分配顺序;拒绝长度头与正文不符、越界人数、畸形截断包及超大包。
|
||||
- 不把扩大总包上限误写成扩大单条短信正文限制;编码长度与字符数量分别校验。
|
||||
|
||||
## 5. 已核对的非问题项与范围限制
|
||||
|
||||
- 本次检查的 Msg_Id/gatewayMessageId/ackMessageId 使用字符串存储,未发现数据库容量缩小。
|
||||
- 客户原始序号、下游 ACK 序号已有 text 存储,没有此次 integer 上限问题,但仍须处理序号 0 的代码语义。
|
||||
- 已查手机号、接入号、正文、原始状态码等数据库列为 text,没有 varchar 长度不足问题;协议封包处的字节长度校验仍需保留。
|
||||
- 长短信 8/16 位引用号、分片数量和编码值可被现有 integer 容纳;语义校验仍须保留,不能只靠数据库类型。
|
||||
- CONNECT 时间戳按 MMDDHHMMSS 编码,最大合法日历组合不超过 1231235959,不属于此次 integer 超限风险。
|
||||
- 本次不是完整 CMPP 一致性认证;ISMG 间路由、所有扩展命令、二进制短信全场景及国际号码产品范围不在本次结论内。
|
||||
|
||||
## 6. 历史数据与应急恢复衔接
|
||||
|
||||
1. 实施前重新取得主任务最终恢复记录,核对原始事件摘要、业务匹配、发送尝试、扣退费、通知与客户 ACK,不直接继续任何旧脚本。
|
||||
2. 迁移只扩大存储能力,不自动重投历史事件、不重新生成通知、不重算金额,也不回写短信成功状态。
|
||||
3. 临时恢复时省略的原始序号,仅在存在原始事件且与记录唯一匹配时才可计划补录。补录审计字段不得重新触发补发、退款或下游推送;需要独立清单和恢复授权。
|
||||
4. 事件匹配必须包含通道/供应商身份、Msg_Id、号码和发送尝试,不以号码单独认领,不能跨客户合并。
|
||||
5. 原始事件可在确认耐久业务接管后按现有恢复流程收尾,但 Inbox matched 不能单独证明短信终态、账务或客户通知已经完成;还须核对收尾工作和最终结果。
|
||||
6. 再次恢复时使用原业务幂等键,尊重已完成的最终决策,禁止为让客户“看到成功”覆盖真实失败。
|
||||
|
||||
## 7. 实施、迁移与发布顺序
|
||||
|
||||
建议同一维护窗口覆盖全部问题;如必须拆批,首批至少完成 FIELD-01~04 并独立闭环验证,FIELD-05/06 必须有明确后续计划。优先级是实施顺序,不代表本轮授权执行。
|
||||
|
||||
1. 固定当前分支、精确提交、工作区保护清单、线上版本;重新盘点受影响调用点和数据规模。将本文用例与需求、设计和测试进度同步。
|
||||
2. 完成字段适配、编解码、序号存在性、状态和长度修复及测试。既有第三方库以仓库内 fork 修改留痕,不顺带升级整套依赖。
|
||||
3. 在隔离 PostgreSQL 上演练旧 schema 升级,保留旧值、NULL、索引、约束及关联,测量迁移锁持有时间、磁盘/WAL 增量和失败回滚。
|
||||
4. integer → bigint 可能引发表重写和强锁;按真实表规模选维护窗口。设置明确 lock_timeout/statement_timeout,超时退出而非无限等待,不在未知流量下直接执行。
|
||||
5. 迁移、Prisma Client 与全部相关进程作为兼容整体交付。约束可按演练结果使用 NOT VALID 后校验,但上线不能留下未登记的未验证约束。
|
||||
6. 授权发布后按 [部署手册](production-deployment.md) 使用标准 `npm run release -- ...`,依次 plan、有效测试证据、preflight、prepare、deploy、verify/status/report。每个目标环境独立核验,不用临时脚本替代应用发布。
|
||||
7. 发布前保存独立数据库/应用恢复资产,确认主任务恢复不会与迁移同时处理同一批数据。需要暂停消费者时明确范围和时长,防止新旧进程交叉写入。
|
||||
8. 发布后核对精确版本、实际列类型、迁移状态、全链路与队列;真实业务发送验收需另有明确环境和流量授权,不能借回归向真实客户发送测试短信。
|
||||
|
||||
回退限制:旧代码/旧 Prisma Client 可能无法读取新写入的大序号。应用回退不代表兼容,更不能把 bigint 直接缩回 integer。保留宽字段,优先前向修复;确需回退时必须证明旧版本兼容、未完成事件可接续。不能删除大值记录来让回退成功,已发送短信和客户已确认回执也无法用数据库快照撤销。
|
||||
|
||||
## 8. 验收用例
|
||||
|
||||
以下全部为新增待执行用例,不计入既有通过数。使用独立隔离数据;mock 只用于隔离,不替代真实 API/PG/Redis/Gateway 证据。
|
||||
|
||||
| 用例 | 场景 | 预期与证据 |
|
||||
|---|---|---|
|
||||
| CMPP-FIELD-T01 | 7 字段依次写入 0、2147483647、2147483648、4294967295 | 真实后端/PG精确保存及读回,JSON不丢精度 |
|
||||
| CMPP-FIELD-T02 | -1、4294967296、小数、NaN、空串及缺失 | 按必填/可空规则拒绝或保留缺失;不误转0,不产生假成功 |
|
||||
| CMPP-FIELD-T03 | 真实回执高序号,单条与批量回调入口 | 耐久接收、匹配、分片聚合、终态及通知闭环 |
|
||||
| CMPP-FIELD-T04 | 上行高序号及重复事件 | 上行入库、应用归属及投递正确,无重复业务记录 |
|
||||
| CMPP-FIELD-T05 | Submit/分片高序号返回 | 提交结果、分片记录及后续回执均可关联 |
|
||||
| CMPP-FIELD-T06 | 3.0 DELIVER_RESP 的大非零 Result | 保存完整错误码,进入失败/重试路径,不判为成功 |
|
||||
| CMPP-FIELD-T07 | uint64 Msg_Id 最大值跨 Gateway/Redis/API/PG/UI | 全链路字符串精确一致,无 Number 中转 |
|
||||
| CMPP-FIELD-T08 | 2.0/3.0 标准60/71字节状态报告收发 | 逐字段、偏移、长度正确;实际TCP对端解析通过 |
|
||||
| CMPP-FIELD-T09 | 3.0 32字节号码字段、最大SMSC_sequence;错版本/截断包 | 不错位,异常显式拒绝;兼容例外仅按批准策略执行 |
|
||||
| CMPP-FIELD-T10 | 客户Submit序号0、4294967295及回卷 | 单条/长短信回执正常,原Msg_Id一致,不漏目标 |
|
||||
| CMPP-FIELD-T11 | 序号0在Gateway重启、重连后恢复 | 使用持久化身份恢复;缺失序号不伪造为0 |
|
||||
| CMPP-FIELD-T12 | CONNECT_RESP.Status=0、5、255、256、4294967295 | 只有0成功;全部非零失败并保留原码 |
|
||||
| CMPP-FIELD-T13 | 3.0 Submit 99人×140字节、编码允许边界 | 3471字节合法包进入正常校验;100人按规范限制拒绝 |
|
||||
| CMPP-FIELD-T14 | 巨大/过小Total_Length、错长度、截断包 | 有界读取与内存占用,明确失败,无崩溃或无界分配 |
|
||||
| CMPP-FIELD-T15 | 旧值/NULL升级,迁移锁超时/中断 | 数据不变、失败可识别、恢复步骤真实演练 |
|
||||
| CMPP-FIELD-T16 | 高序号重复、乱序、跨尝试、并发与故障接管 | 关联不串客户/尝试;不重复补发、扣退费或最终通知 |
|
||||
| CMPP-FIELD-T17 | 真实下游ACK与断线重连 | 区分待发送、已发未确认和客户已确认,不将入队当送达 |
|
||||
| CMPP-FIELD-T18 | 应急省略序号的历史记录与原始事件核对 | 只补审计不重开业务;证据不足保留待核查 |
|
||||
|
||||
自动检查按 [测试计划](testing-plan.md) 执行 API 定向/全量测试、类型检查、构建及质量门禁,Gateway `go test ./...`、`go vet ./...`。覆盖 vendored 协议库本身的测试:不能默认 Gateway 的 `./...` 会跨越嵌套 Go module。若影响前端接口或展示,补前端定向与必要回归、真实页面验收。保留未执行原因,不以编译通过替代协议互通。
|
||||
|
||||
停止条件:新增重复Submit、账务不一致、终态被覆盖、租户串联、无法恢复的协议解析异常、持续积压或迁移锁超时。停止放量并保留证据,不靠手工改最终状态掩盖失败。
|
||||
|
||||
## 9. 完成标准与交接
|
||||
|
||||
仅在以下事实全部具备后,才能声明目标环境整改完成:
|
||||
|
||||
- 7字段覆盖、版本化编解码、序号0、连接状态与收包上限已实现,并满足选定发布范围。
|
||||
- 上述用例有对应证据,真实PG及TCP互通通过;历史数据兼容和故障恢复经过验证。
|
||||
- 精确提交已通过标准发布,目标环境版本与实际schema一致。
|
||||
- 原始事件、耐久接收、业务终态、补发尝试、账务和客户ACK分层对账,无未解释缺口;客户离线等外部阻塞单独列明。
|
||||
- 更新需求、设计、系统测试用例和测试进度,分别报告本地修改、提交、推送、测试部署、预生产部署状态。
|
||||
|
||||
目标环境实施人接手时重新核对主任务最终恢复结果和现场,不从本方案推定任何待处理队列已排空或获得生产操作授权。
|
||||
|
||||
## 10. 2026-09-20 实施审查与本地验收
|
||||
|
||||
### 实施基线与规则补充
|
||||
|
||||
- 最新本地基线为 `b24cd7c`(模板拒收策略与运营页面),已包含 `c20c224` 的终态/发送尝试归属修复;已核对远端 main 仍为 `5e4d644`,本轮不推送。其他会话未提交文件及共享文档原有差异保留。
|
||||
- 五个 `sequenceId` 与两个 `ackResult` 改为 nullable BigInt,迁移 `20260920160000_cmpp_protocol_uint32` 在一个事务内扩容并加入 0..4294967295 检查,锁等待 5 秒、单语句超时 5 分钟。负数历史值阻断并回滚,NULL 不回填。发布前需要按真实表规模重新评估重写/WAL/锁时间。
|
||||
- `protocol-uint32.ts` 明确执行数值校验、BigInt 写入、校验后读回;API 与 callback 使用专用字段响应转换,仅处理 `sequenceId`/`ackResult`,金额 BigInt 和日期保持原有行为。协议输入不接受数字字符串、空串、浮点及越界;历史文本 Submit 序号单独解析,字符串 `"0"` 有效,空白/缺失无效。Msg_Id 保持十进制字符串。
|
||||
- 版本化 `PackVersion`/`UnpackVersion` 严格检查 2.0/2.1 的 60 字节与 3.0 的 71 字节。上游、协议日志、下游均显式传版本;原 Pack/Unpack 仅作为 2.0 兼容调用保留,3.0 不自动接受 60 字节。目的号码字段为 21/32 字节,SMSC_sequence 最后 4 字节,超长字段不能截断。
|
||||
- 原 Submit 序号使用可空指针区分缺失与 0;入站 JSON 不省略 0。长短信首段判断改为实际段位置。上游分配序号时避开在途 Submit/心跳,下游 ACK 注册冲突则保留原记录、返回可重试错误,不覆盖待确认回执。
|
||||
- CONNECT_RESP 状态全程 uint32,非 0 一律失败并保留完整错误码。3.0 收包上限复用现有 Submit 最大长度常量 3491,覆盖 99 号码、140 字节的 3471,以及 ASCII 159 字节的 3490;规范原文为 ASCII <160,因此 160 字节拒绝。3491 只是保守的有界内存上限,不代表允许 160 字节内容。打包验证号码个数和数组、声明长度和实际内容一致;解包拒绝截断和多余字节。
|
||||
- T16 并发真实验收复现一个相邻缺陷:可选 connectionId 未传时 Prisma 的空 update upsert 可能退化为先查后插,两个首次相同回执发生 P2002。本轮仅在该错误后按相同 receiptKey 回读已持久化记录再确认接收;没有对应记录或其他数据库错误仍抛出,避免假成功。
|
||||
|
||||
### 验收映射
|
||||
|
||||
| 用例 | 本地证据与结果 | 尚未覆盖的目标环境项 |
|
||||
|---|---|---|
|
||||
| T01–T06 | 新脚本 `tools/testing/verify-protocol-fields.mjs` 用真实 Nest callback、PG、Redis 验证四个边界、七字段、单/批回执、Submit 分片、上行去重、大 ACK 非成功、非法输入无写入;通过 | 真实供应商/客户在线业务回归 |
|
||||
| T07 | 最大 Msg_Id `18446744073709551615` 经过 Redis/HTTP/Prisma 保持字符串;Go TCP/回执往返不截断 | 线上供应商端到端互通 |
|
||||
| T08–T09 | vendored codec 与 upstream tests 验证 60/71 字节、32 字节号码、最大 SMSC、错误版本/截断;下游 2.0/3.0 TCP 回执验证通过 | 实际通道 3.0 是否存在非规范 60 字节回执需发布前抽样 |
|
||||
| T10–T11、T17 | 入站序号 0 JSON、缺失与 null 区分;新连接无原消息内存映射时恢复 Msg_Id,2.0/3.0 真 TCP DELIVER/DELIVER_RESP Result=0;最大/0 序号冲突保护测试通过 | 实际客户端重连验证 |
|
||||
| T12–T14 | 真 TCP CONNECT 状态 0/5/255/256/4294967295;99 号码 3471/3490;100 号码、超长内容、截断/多余内容、巨大/过短头拒绝;通过 | 目标环境日志、吞吐与异常隔离观察 |
|
||||
| T15 | 全量 113 个已提交基线+本轮迁移在新隔离库成功;缩小结构演练末表非法值导致前面 DDL 整体回滚、5 秒锁超时回滚、NULL/0/2147483647 与七个索引保留 | 生产规模 WAL/耗时、发布切换与实际备份恢复未演练 |
|
||||
| T16 | 同一大序号回执并发接收、重复批回调、相反迟到回执;另现有 receipt-finality/attempt-completion 的并发、跨尝试、故障事务恢复真实 PG 测试通过 | 整个 Gateway→Redis→API→客户单进程链路未联合运行;各边界分别验证 |
|
||||
| T18 | 模拟已持久化但省略序号的历史回执,重复接收后仍 NULL,终态/通知数量不重新打开;通过 | 本轮不对线上应急历史数据做字段回填 |
|
||||
|
||||
验收脚本要求**新建空的本机 `cmpp_qa_*` 数据库**,应用基线及本轮迁移后构建 API,设置 `PROTOCOL_TEST_DATABASE_URL` 和 `PROTOCOL_TEST_REDIS_URL`。最高 Msg_Id 为固定边界 fixture,不能把多轮 fixture 混在同库当成新的发送尝试。脚本只连接本机,通道禁用、地址 127.0.0.1:1,不启动发送工作进程;产生合成业务/通知记录,不向真实运营商或客户发报文。
|
||||
|
||||
证据目录 `.local-data/protocol-fields-20260920/` 不入 Git。关键日志为 `real-chain-verified.log`、`migrate-verified.log`、`api-coverage-final.log`、`api-incremental.log`、`go-final.log`、`gocmpp-final.log`、`receipt-finality.log`、`attempt-completion.log`。最终迁移小样本为七表 21 行,扩容阶段约 106ms、WAL 81800 字节;不是线上容量承诺。保留首次 Redis 从错误工作目录读取旧 RDB 而启动失败、重复使用固定边界 fixture 库而匹配冲突、以及实际 P2002 并发失败日志,最终以专用 Redis 目录和全新库复验。
|
||||
|
||||
本地 Redis 为 5.0.14.1,实际 Stream 读写通过,但低于 BullMQ 推荐的 6.2;没有以此宣称发布环境队列版本验收。PG 驱动给出并发 query 弃用提示,当前测试通过,未修改驱动。API 响应结构保持数字/字符串不变,无前端代码或 CSS 改动;未重复浏览器验收。部署时必须一起发布 schema、API/callback/相关 worker 及 Gateway,旧 Prisma 客户端不能视为已支持超 31 位数据;不能通过缩回 integer 做应用回滚。
|
||||
|
||||
门禁:API 全量和增量覆盖率各 87 套 / 990 项通过,TypeScript 构建通过;Gateway 全量测试及根模块 vet 通过,vendored 模块测试通过;5 个队列契约、变更代码 lint(0 error,32 个存量 any warning)、格式检查和 diff 检查通过。额外运行 vendored 模块完整 vet 发现两个原有 stdmethods 提示:`packetWriter.WriteByte`/`packetReader.ReadByte` 使用累积错误接口而非标准 io 签名;本轮未更名整个协议库,记录为既有待治理项,不宣称该额外检查通过。没有通过禁用检查隐藏问题。
|
||||
|
||||
测试在保留其他会话修改的当前工作区执行,提交仅纳入本轮文件和共享文档新增段落;这些本地结果不能冒充标准发布工具绑定精确提交的发布证据。隔离 PostgreSQL、Redis 已关闭,数据/日志保留。上线前仍应按标准工具从精确提交构建并生成对应验证证据。
|
||||
Reference in New Issue
Block a user