Files
msgexchange-v2/docs/contracts.md
T
windyboy 729e102b8e docs(lifecycle): 补齐清除生命周期与逐对象归档边界
- design.md 9.3 扩为「生命周期与清除」:清除通则、逐对象生命周期表、
  处理终态归档判据(终态 ∧ 回填了结 ∧ 终局后到期)与时间常数排序
- contracts.md 新增 C-16:回填放弃清单在对应信箱边界清除前必须保持可查
- invariants.md 缺口索引新增 G-HST-RETENTION、G-FLIGHT-HIST-RETENTION、
  G-REQ-TRACK-RETENTION
- flight-state.md 补航班历史存储保留期开放项
- 同步 architecture.md / user-stories.md 的 9.3 交叉引用
2026-09-13 10:49:48 +08:00

93 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 对外契约与待确认事项
本文件是本系统与外部对手方之间**承诺与要求**的唯一出处,也是待确认事项(`Q`)的唯一台账。条款编号 `C-x`、问题编号 `Q-x` 稳定不变;条款被取代时标 `[作废 by C-y]` 并保留原文,不静默改写。
读者:库方(共享 MySQL 管理方)接口人、上游(CIIMS / AODB / SIS)接口人、本系统开发与运维。
条款状态词只有三种:`[待确认 Q-x]`(未取得对方书面确认)、`[已确认 YYYY-MM-DD]`(对方书面确认且已回写)、`[我们单方承诺]`(不依赖对方,已生效)。
## 术语
| 术语 | 含义 |
|---|---|
| 上游 | 向信箱写入报文的源头系统(CIIMS、AODB 等)。 |
| 信箱 | 共享 MySQL 的入站表 `CMINMSGS`;出站方向为 `COUTMSGS`。 |
| 库方 | 共享 MySQL 的管理方;表结构变更与数据清除只能由库方执行或书面授权。 |
| 处理标记 | 信箱行上表示「本系统已处理」的约定字段;逻辑名 `DATE_PROCESSED` / `STATUS`,实际列名以库方契约为准。本系统只把空标记写成已处理值,不回撤、不覆盖。 |
| 落信 | 报文进入信箱(`CMINMSGS` 存在该行),执行方是上游。 |
| 入队 | 本系统在自有 PG 建立 `PROC_STATE` 记录,开始处理。 |
| 已回填 | 本系统已把处理标记写回该信箱行。 |
| 投递确认 | 投递目标已接受且本地 `MSG_EVENT` 已置 `SENT`;不表示业务消费者已消费。 |
| 自有 PG | 本系统唯一的业务数据库 PostgreSQL;与信箱之间不存在跨库事务。 |
## A. 共享信箱(库方)
### A.1 ID 与可见性
- **C-1** ID 单调:信箱 ID 按提交顺序分配,已发布水位之下不再出现更小的新 ID。`[待确认 Q2]`
- **C-2** ID 分配 → 事务可见时延上界由库方**直接给出**。该值决定空洞老化阈值;**不可由 SIS 报文 `Expiry` 推导**`Expiry` 是报文保留与传输恢复口径,与「ID 分配后多久对读事务可见」不是同一个量)。`[待确认 Q2]`
- **C-3** ID 空间不复位、不复用、不回退:含表轮换、备份恢复、`AUTO_INCREMENT` 归零。采用整表轮换方案时,新表种子必须 ≥ `max(ID)+1`,保证 ID 不断链;本系统的水位 `W` 是不可逆单游标,ID 回退会导致其后所有行永久不可见。`[待确认 Q2]`
- **C-4** 报文行不可变:同一业务身份(`SNDR|TYPE|STYP|SEQN`)的重发必为同一内容。若上游会以同一身份改发正文,需要另定识别规则(`Q15`)。`[待确认 Q15]`
### A.2 保留与清除(标记、保留期、清除前提)
- **C-5** 处理标记值集与写权限:本系统只写入库方认可的 legacy 值集内的「已处理」值(默认 `PROCESSED`),只写空标记、不回撤、不覆盖;内部原因(死信、重复、放弃)记录在自有 PG,**不在信箱新增枚举**。`[待确认 Q7]`
- **C-6** 清除语义必须是「标记 + 保留期」:打标本身不触发清除,触发条件是「到达保留期 `R_keep`」且「边界内全部行已打标」。若库方语义是「打标即可清除」,则清除前置条件不成立,且**增大 `R` 无法补救**,必须另行约定保留期或引入独立原文保留通道。`[待确认 Q7][待确认 Q9]`
- **C-7** 保留期下界(本文件是唯一定义处):
`R_keep ≥ max(人工重放期限 + 人工处置期限, 审计期限, 回填重试上限)`
这是「重放窗口内原文仍在」的**唯一保证来源**。报文在 CIIMS 的 `Expiry`480 分钟量级,SIS §3.16)可作为原文保留期的参照,但它是报文有效期,不等于本处所需的保留期。`[待确认 Q6][待确认 Q9]`
- **C-8** 清除前置条件(本文件是唯一定义处):执行清除时,边界内**每行必须已有终局**——即「已持有处理标记」**或**「已登记在本系统的回填放弃清单中且经人工对账确认」。放弃行不写标记,未达终态的行顺延至处理完成后清除;本系统不执行 DDL,也不写共享历史表。`[待确认 Q7][待确认 Q9]`
- **C-9** 清除执行方与方案:清除由库方执行或书面授权执行。方案 A(按 `DATE_RECEIVED` 日分区 + `TRUNCATE/DROP PARTITION`)为首选;方案 B`CREATE TABLE ... LIKE` + 保留窗复制 + `RENAME TABLE` + 对账 + `CMINMSGS_HST` 归档 + `DROP`)为备选。现场 MySQL 版本与分区 DDL 能力待确认。`[待确认 Q9]`
- **C-10** 时间语义:时间比较与换算统一采用机场时区 `Asia/Shanghai` 及明确类型转换;`DATE_RECEIVED` 由上游/库方写入,其时钟基准需可解释(见 `PRE-4`)。`[待确认 Q7]`
### A.3 原文保留与重放
- **C-11** 重放窗口内的原文必须可读:legacy 现役按接收超 1 天归档并删除 `CMINMSGS`;若沿用该窗口,则与 `C-7` 冲突,须以 `C-7` 为准。`[待确认 Q9]`
- **C-12** 若原文被提前清除(违反保留契约),本系统的死信处置不变,按契约违例走运维追责;该情形不改变 `C-8` 的清除前提。`[我们单方承诺]`
### A.4 我们向库方的承诺
- **C-13** 只读约定区间的信箱行(`ID > W`),单活动实例运行,不引入并行消费者。`[我们单方承诺]`
- **C-14** 不建表、不改表结构、不迁移 schema、不写共享历史表;兼容 HTTP 入口按既有契约写入入站信箱。`[我们单方承诺]`
- **C-15** 处理标记只写 `C-5` 认可的值,不回撤、不覆盖已有非空标记。`[我们单方承诺]`
- **C-16** 回填放弃清单在对应信箱边界被清除前必须保持可查:`C-8` 以本清单作为清除授权证据之一,该证据不得随处理记录的归档或清除而消失。`[我们单方承诺][待确认 Q7][待确认 Q9]`
## B. 上游(SIS / AODB
- **C-20** 业务身份四元组 `SNDR|TYPE|STYP|SEQN` 的语义由上游定义;`SEQN` 的取值范围与回绕见 SIS §2.8.1。**重置周期未知**,它决定业务身份是否加入日期边界(默认不加)。`SNDR` 取值域也需对拍(SIS 为 AODB/RMSlegacy 实发 OSH5 等)。`[待确认 Q11]`
- **C-21** `FLID` 在保留期内不复用。若复用,事件版本(`STATE_VERSION`)必须按 incarnation 作用域,否则「保留最新版本」的合并规则会把新航班的事件压掉,旧 tombstone 也可能删掉在用航班。`[待确认 Q16]`
- **C-22** 报文不可变(同 `C-4`)。`[待确认 Q15]`
- **C-23** 请求/应答回显契约:目标优先按已确认的回显字段精确匹配;回显未确认时的降级匹配(同类开放请求且报文 `DTTM ≥ sentAt`)存在跨代误配风险,必须明确接受并审计,不得宣称精确关联。比较前统一时区与时间单位。`[待确认 Q5]`
- **C-24** 出站信箱 `COUTMSGS`:消费方与消费顺序、`COUTMSGS_ACK_DATE_RECV` / `COUTMSGS_ACK_RESEND_TIMES` / `COUTMSGS_DATE_SENT` / `COUTMSGS_ERROR` 各列语义与写入责任、出站行清除责任与保留期、落信成功但本地未置 `SENT` 时的重复写入风险及下游去重契约,均未确认。本系统对出站的交付承诺只到**落信**为止。`[待确认 Q10]`
- **C-25** 主 / 共享删除顺序与 EROR 回报:SIS 要求删主航班前先删子共享航班,顺序不符时 RMS 应向 AODB 回发 ERORSIS §1.6.1-1.d,事件定义 SIS §4.8);现行设计为幂等原子级联、不回发 EROR。二选一。`[待确认 Q14]`
- **C-26** 日计划缺失可选字段的语义:SIS 要求最新日计划中未发送的可选字段表示 AODB 已无该数据、子系统应删除本地值(SIS §3.16 注释 4,RESP 同格式见 §3.17),与现行「未携带字段保留」相反。`[待确认 Q13]`
- **C-27** 历史积压批次中「不再处理」的确认主体、审批留痕与跳过值集。`[待确认 Q12]`
### B.1 我们向上游的承诺
- **C-28** 兼容 HTTP 入口的响应只表示**接收结果**,不表示业务处理成功:目标为现役 `ResponseDto``is_success` / `body`),请求体上限暂定 10MB;请求媒体类型、字符集与失败响应仍需与现役逐项对拍。`[待确认 Q3]`
- **C-29** 对外投递按**至少一次**设计,不承诺端到端恰好一次;Kafka 消息的 key 为 `FLID`,同一 `FLID` 内保序,跨 `FLID` 不承诺顺序。`[待确认 Q4]`
## C. 待确认事项台账(Q
| 编号 | 事项 | 当前假定 | 阻塞 | 状态 |
|---|---|---|---|---|
| Q1 | 权威存储(内部方向) | 自有 PG 单库权威 + 无损明细;现场供库目标 Oracle 11g | — | 已定案(内部),Oracle 适配与部署验收另计 |
| Q2 | 信箱 ID 单调、ID 分配→事务可见时延上界、ID 空间不复位;空洞与迟到处置 | 时延按 5 分钟 `max-commit-delay`(**缺少依据的占位值**,不可由 SIS `Expiry` 推导) | 发现完整性声明、空洞老化阈值、水位不可逆性 | 未确认 |
| Q3 | HTTP 契约:媒体类型、字符集、错误码、查询接口对拍 | 目标与上限见 `C-28` | 兼容入口验收 | 未确认 |
| Q4 | Kafka wire:发送粒度、key、去重标识、分区与批次确认 | 逐 `FLID` 发送,key=`FLID` | 投递契约 | 未确认 |
| Q5 | 请求匹配:回显字段可靠性与降级匹配 | `RQFD` 60 秒 / `RQRD` 30 秒超时 | 请求跟踪闭环 | 未确认 |
| Q6 | 重放期限与人工处置期限的取值(唯一作用是决定 `R_keep` 下界) | `R` = 30 天;重放/处置期限未定 | `R_keep` 取值 | 未确认 |
| Q7 | 处理标记值集与写权限、原文保留期、处理时间语义 | 写入 `PROCESSED` | 回填值集、保留期下界 | 未确认 |
| Q8 | 逐类覆盖清单(积压摸底的类型分布依据) | — | 积压处置与逐类矩阵 | 暂缓(现阶段不处理) |
| Q9 | 清除执行方与 DDL 授权、方案 A/B 选型、分区能力 | 首选方案 A | `R_keep` 与清除边界 | 未确认 |
| Q10 | 出站消费方、ACK 列语义、出站清理与去重契约 | — | 出站信箱 | 未确认 |
| Q11 | 上游 `SEQN` 重置周期与业务身份的日期边界 | 不含日期边界 | 身份算法 | 未确认 |
| Q12 | 积压批次「不再处理」的确认主体、审批留痕与跳过值集 | — | 积压跳过处置 | 未确认 |
| Q13 | 日计划缺失可选字段的删除语义 | 保留未携带字段;真实消息与 SIS 冲突时以真实消息为准 | 快照合并 | 暂缓(测试前不处理) |
| Q14 | 主/共享删除顺序与 EROR 回报义务 | 幂等原子级联 | 出站事件类型 | 未确认 |
| Q15 | 上游是否会以同一业务身份改发正文(决定是否需要区分「重复」与「改发」) | 假定期望不可变(`C-4` | 身份去重语义 | 未确认 |
| Q16 | `FLID` 重用语义(决定版本是否按 incarnation 作用域) | 假定不复用(`C-21` | 事件合并与 tombstone | 未确认 |
Q 的答复只在本表就地更新(补「结论」与日期),并触发 [README.md](README.md)「维护清单」的落地 4 步;不另开文件。