Files
msgexchange-v2/docs/specification.md
T
windyboy 723b3e4c09 docs(acm2-75): 精简规范引言并重写术语表
- 删除引言段:唯一出处清单、编号规则与空缺说明按评审结论去除
- 术语表逐行改写为平话:库方收敛为 CIIMS adapter 方(信箱表在其 MySQL,表结构变更与清除归它,机制未定);上游收敛为 CIIMS adapter 写入,AODB 经它落信
- 落信涵盖兼容 HTTP 入口;处理标记标注与需求文档「处理时间」的对应
- 术语行去掉内部表名、编号括注与管道术语指针;处理完成、Redis 投影按 US-05/US-07 口径收窄 Redis 条件
2026-09-14 17:56:18 +08:00

239 lines
30 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.
# 规范:术语、契约、前提、不变量与声明边界
## 1. 术语
| 术语 | 含义 |
|---|---|
| 上游 | 报文的写入方。现在是 CIIMS adapter,它把 AODB 下发的报文写进信箱。 |
| 信箱 | CIIMS adapter 的 MySQL 里用于消息交换的表——入站 `CMINMSGS`、出站 `COUTMSGS`;报文由 adapter 写入,网关读取。 |
| 库方 | CIIMS adapter 方。信箱表在它的 MySQL 里,表结构变更与数据清除由它执行,机制未定;本系统只读消息、写回处理标记,不改表结构、不清数据。 |
| 处理标记 | 信箱行上表示「已处理」的字段,需求文档说的「处理时间」就是它。本系统只把空标记写成已处理值,不回撤、不覆盖。 |
| 落信 | 报文进入信箱,成为其中一行。写入的是 adapter 或兼容 HTTP 入口。 |
| 入队 | 本系统在自有 PG 给这条报文建立一条处理记录,开始处理。 |
| 已回填 | 本系统已把处理标记写回该信箱行。 |
| 处理完成 | 消息处理完了:业务数据已写入自有 PG,该写的 Redis 投影也已写成功。 |
| 投递确认 | 发出去的消息对方已接收,本系统的投递记录也记成已发送;这不代表对方的业务已经消费。 |
| Redis 投影 | 本系统写进 Redis、供查询用的航班数据;完整数据在本系统的 PostgreSQL 数据库里。 |
| 自有 PG | 本系统自己的业务数据库 PostgreSQL,处理结果都存在这里;与信箱之间没有跨库事务。生产环境用 PostgreSQL 还是 Oracle 11g,还没定。 |
| admin-api | 下游查询系统;直接读本系统写入的静态参考数据表,不向本系统提供数据。 |
条款后面的状态标记有四种:`[待确认 Qn]`=还没拿到对方确认;`[已确认 YYYY-MM-DD]`=对方已确认并记录在此;`[我们单方承诺]`=不等对方、自己已生效的对外承诺;`[我们自证]`=本系统自身的部署事实,无需确认。
## 2. 契约
读者:库方(共享 MySQL 管理方)接口人、上游(CIIMS / AODB / SIS)接口人、本系统开发与运维。
### 2.1 共享信箱(库方)
**ID 与可见性**
- **C-1** ID 单调:信箱 ID 按提交顺序分配,已发布水位之下不再出现更小的新 ID。`[待确认 Q2]` **[作废 by C-30]**
- **C-2** ID 分配 → 事务可见时延上界由库方**直接给出**。该值决定空洞老化阈值;**不可由 SIS 报文 `Expiry` 推导**`Expiry` 是报文保留与传输恢复口径,与「ID 分配后多久对读事务可见」不是同一个量)。`[待确认 Q2]` **[作废 by C-30]**2026-09-14:扫描改为处理标记谓词,按轮自愈,可见时延不再决定任何阈值。)
- **C-3** ID 空间不复位、不复用、不回退:含表轮换、备份恢复、`AUTO_INCREMENT` 归零。采用整表轮换方案时,新表种子必须 ≥ `max(ID)+1`,保证 ID 不断链;本系统的水位 `W` 是不可逆单游标,ID 回退会导致其后所有行永久不可见。`[待确认 Q2]`
- **C-4** 报文行不可变:同一业务身份(`SNDR|TYPE|STYP|SEQN`)的重发必为同一内容。若上游会以同一身份改发正文,需要另定识别规则(`Q15`)。`[待确认 Q15]`
**保留与清除(标记、保留期、清除前提)**
- **C-5** 处理标记值集与写权限:本系统只写入库方认可的 legacy 值集内的「已处理」值(默认值见 [reference.md](reference.md) `PARAM:mailbox.processed-value`),只写空标记、不回撤、不覆盖;内部原因(死信、重复、放弃)记录在自有 PG,**不在信箱新增枚举**。`[待确认 Q7]`
- **C-6** 清除语义必须是「标记 + 保留期」:打标本身不触发清除,触发条件是「到达保留期 `R_keep`」且「边界内全部行已打标」。若库方语义是「打标即可清除」,则清除前置条件不成立,且**增大 `R` 无法补救**,必须与库方另定保留期。`[待确认 Q7][待确认 Q9]`
- **C-7** 保留期下界(本文件是唯一定义处):
`R_keep ≥ max(审计期限, 回填重试上限)`
报文在 CIIMS 的 `Expiry`480 分钟量级,`SIS:3.16`)可作为原文保留期的参照,但它是报文有效期,不等于本处所需的保留期。`[待确认 Q7][待确认 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]`
**原文保留**
- **C-11** legacy 现役按接收超 1 天归档并删除 `CMINMSGS`;若沿用该窗口,则与 `C-7` 冲突,须以 `C-7` 为准。`[待确认 Q9]`
- **C-12** 若原文被提前清除(违反保留契约),本系统的死信处置不变,按契约违例走运维追责;该情形不改变 `C-8` 的清除前提。`[我们单方承诺]`
**我们向库方的承诺**
- **C-13** 只读约定区间的信箱行(`ID > W`),单活动实例运行,不引入并行消费者。`[我们单方承诺]` **[作废 by C-30]**
- **C-14** 不建表、不改表结构、不迁移 schema、不写共享历史表;兼容 HTTP 入口按既有契约写入入站信箱。`[我们单方承诺]`
- **C-15** 处理标记只写 `C-5` 认可的值,不回撤、不覆盖已有非空标记。`[我们单方承诺]`
- **C-16** 回填放弃清单在对应信箱边界被清除前必须保持可查:`C-8` 以本清单作为清除授权证据之一,该证据不得随处理记录的清除而消失。`[我们单方承诺][待确认 Q7][待确认 Q9]`
- **C-30** 信箱读取口径:本系统按配置周期扫描信箱,谓词为「处理标记为空」,按编号升序读取、每批有上限;单活动实例运行,不引入并行消费者。编号即到达顺序:已读过的编号之后不应再出现更小的新编号(较小编号迟提交只会被发现得晚,不会丢;ID 空间不复位、不复用见 `C-3`)。`[我们单方承诺]`(顺序依据 `[待确认 Q2]`
### 2.2 上游(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`:消费方为 CIIMS adapter。未确认项:消费顺序、`COUTMSGS_ACK_DATE_RECV` / `COUTMSGS_ACK_RESEND_TIMES` / `COUTMSGS_DATE_SENT` / `COUTMSGS_ERROR` 各列语义与写入责任、出站行清除责任与保留期、落信成功但本地未置 `SENT` 时的重复写入风险及下游去重契约。本系统对出站的交付承诺只到**落信**为止。`[待确认 Q10]`
- **C-25** 删除主航班时级联删除其共享航班,原子提交、不允许删一半;不向 AODB 回发 EROR。`[我们单方承诺]`2026-09-14 定案,依据 `US-06` AC2SIS 原要求见 `SIS:1.6.1-1.d``SIS:4.8`。)
- **C-26** 日计划快照中未携带的可选字段视为 AODB 已删除该值,本地同步清除。`[我们单方承诺]`2026-09-14 定案,依据 `US-07` AC3SIS 语义见 `SIS:3.16-note-4``SIS:3.17`。)
- **C-28** 兼容 HTTP 入口的响应只表示**接收结果**,不表示业务处理成功:成功返回信箱编号,失败不返回编号;目标为现役 `ResponseDto`。请求媒体类型支持 `text/xml``application/xml``text/plain`,默认 UTF-8;请求体上限取值(暂定 10MB)与失败响应样例仍需与现役逐项对拍。仅限内网使用,来源由网络层限制。`[待确认 Q3]`
- **C-29** 对外投递按**至少一次**设计,不承诺端到端恰好一次;Kafka 消息的 key 为 `FLID`,同一 `FLID` 内保序,跨 `FLID` 不承诺顺序。`[待确认 Q4]`
### 2.3 下游(admin-api
- **C-31** admin-api 直接读取本系统写入的静态参考数据表;本系统不调用 admin-api,也不从 admin-api 拉取、补全或合并任何数据。`[我们单方承诺]`
## 3. 前提(外部提供)
前提失效时不变量必须整体重估。
| 编号 | 前提 | 若不成立的影响 | 状态 |
|---|---|---|---|
| PRE-1 | 信箱消费权排他:同一时刻只有一个系统有权处理、打标、判定可清除(迁移期由切流规程保证单一权威写者) | 采集谓词、身份去重、清除前提全部失效 | `[待确认]`(切流由运维规程保证,上线前另立) |
| PRE-2 | 信箱 ID 分配顺序即到达顺序:见 `C-30` | 「编号即到达顺序」的顺序声称失去依据 | `[待确认 Q2]` |
| PRE-3 | ID 空间不复位、不复用、不回退:见 `C-3` | 处理记录按信箱编号唯一的前提被破坏,同编号可能重复登记 | `[待确认 Q2]` |
| PRE-4 | 报文的 `DATE_RECEIVED` 时钟基准可解释(偏斜在有界范围内) | 跨系统时间比较(`RECEIVED_AT` 与本地 `NOW`)会提前或推迟判定 | `[待确认 Q7]` |
| PRE-5 | 单活动实例运行(信箱读取不加锁) | 并行读会让「已处理」判定互相踩踏 | `[我们自证]`(部署约束,见 architecture.md |
| PRE-6 | 信箱与自有 PG 之间没有跨库事务 | 回填、清除都不能声称原子 | `[我们自证]`(架构事实) |
| PRE-7 | 报文不可变:同一业务身份的重发必为同一内容:见 `C-4` | 上游改发会被判为重复并静默跳过 | `[待确认 Q15]` |
| PRE-8 | `FLID` 在保留期内不复用:见 `C-21` | 「保留最新版本」的合并规则可能压掉新航班事件,旧 tombstone 可能删掉在用航班 | `[待确认 Q16]` |
## 4. 不变量
### 4.1 管道
- **INV-1** 五个独立事实互不替代:落信 / 入队 / 处理完成 / 已回填 / 投递确认各有独立证据,前一个不蕴含后一个。
- **INV-2** 水位与入队同事务:不允许出现「水位已推进、消息未入队」的持久化状态;水位只增不减,遇空洞即停,只有判定为永久空洞才放行,且放行只跳过空洞本身、不越过任何已存在的行。**[作废 by INV-2b]**
- **INV-2b** 扫描谓词与幂等登记:每轮按编号升序读取「处理标记为空」的信箱行,每批有上限;同一编号只登记一次(`INV-9`);重复扫描与重启恢复不重复登记、不重复处理、不丢行;终态但未回填的行会被重复读到,按已有记录幂等跳过。
- **INV-3** 队头唯一:任一时刻只有一个可执行队头(最小未完成 `MSG_ID``PENDING``FAILED` 都占位);`FAILED` 未退避到期时后续消息不得越过。
- **INV-4** 只领取已发现的行:主泵只领 `MSG_ID ≤ W`;水位之外的行只可能来自兼容入口,必须等水位追平后按序处理。**[作废 by INV-2b]**(水位取消,兼容入口写入的行即普通行。)
- **INV-5** 发现与处理互不阻塞:收报只看 `ID > W`,不以处理标记为谓词;终态而未回填的行不阻断后续消息的发现。**[作废 by INV-2b]**
- **INV-6** 处理终态不可逆:已提交的 `SUCCEEDED` 不因回填或投递失败回改。
- **INV-7** 处理标记单调:任何路径只把空标记写成已处理值,不回撤、不覆盖。
- **INV-8** 回填只针对终态(`PENDING` / `FAILED` 永不写标记);「还欠一次回填」的事实与终态由**同一条语句**落库,不存在第二处落账。
- **INV-9** 一信一行、一身份一记录:`PROC_STATE``MSG_ID` 唯一;同一业务身份至多绑定一条有效处理记录。
- **INV-10** 对外投递至少一次;端到端恰好一次不在交付范围。
### 4.2 航班域
- **INV-11** 自有 PG 的航班当前态是唯一权威;信箱、Kafka、展示视图都不是权威。**[作废 by INV-11b]**
- **INV-11b** 自有 PG 的航班当前态是唯一权威;信箱、Redis 投影、Kafka、展示视图都不是权威。
- **INV-12** `FLID` 唯一;已写入非空的 `OPERATION_DAY` 不可改变。
- **INV-13** 每个航班每次成功状态写入单调推进 `STATE_VERSION`;重复消息不重复推进。
- **INV-14** 报文未携带的字段不被隐式清空;集合按完整合并结果写入,保留输入顺序与源序号。**[作废 by INV-14b]**
- **INV-14b** 增量报文(FLOP/ADFT)未携带的字段不被隐式清空;集合按完整合并结果写入,保留输入顺序与源序号。日计划快照不适用本条(`INV-15b`)。
- **INV-15** 缺席于某个日计划不构成删除理由;删除只由 FDEL 或受控历史清理触发。**[作废 by INV-15b]**
- **INV-15b** 日计划快照以 AODB 下发为准:快照里没有的航班删除——标记已删除、登记删除事件、从 Redis 投影移除;快照里未携带的字段视为 AODB 已删除该值,本地同步清除(`US-07` AC2/AC3)。
- **INV-16** 外部副作用(回填、Kafka 投递、出站信箱)失败可重试,但不回滚已提交的本地业务结果。
- **INV-17** 状态变更、待发事件、处理终态与回填意图在同一 PG 事务内原子提交。**[作废 by INV-17b]**
- **INV-17b** 状态变更与待发事件在同一 PG 事务内提交;处理终态与回填意图在同一 PG 事务内提交,且该事务在 Redis 投影写成功之后(`INV-23`)。日计划例外:分批写入,每批一个事务(状态变更 + 待发事件),终态与回填意图在整包完成后同一事务提交;失败不标记已处理,下轮整包重新处理(`US-07` AC4)。
- **INV-18** 航班表的写者集合是「主泵处理器」与「历史清理」;两者必须互斥(同一 `PIPELINE_LOCK`,或清理在同一事务内复查判据后再删除),不得出现清理删除与处理器更新同一 `FLID` 的竞态。
- **INV-19** 整包校验失败或运营日冲突时整包不落地,既有状态与版本保持不变。
- **INV-20** 处理器幂等:同一消息重复执行只产生一次业务效果。身份唯一只防「重复记录」,不防「重新执行」;SIS 25 类与经 `Q8` 定案启用的 legacy 子类型完成逐类幂等矩阵前,本条**不可声明**(`G-FLOP-IDEMPOTENT`)。**[作废 by INV-20b]**
- **INV-20b** 处理器幂等:同一消息重复执行(失败重处理、重复发现)只产生一次业务效果。身份唯一只防「重复记录」,不防「重新执行」;逐类幂等矩阵(SIS 25 类与现场延续的 7 类)补全前,本条**不可声明**(`G-FLOP-IDEMPOTENT`)。
- **INV-21** `MAFL` 是派生投影:内容恒等于「`STATE = ACTIVE``MAID = 主航班 FLID`」的子航班集合(元素 `FLID` + `FLNO`,按 `FLID` 升序),不落库、不从入站解析;自引用与悬挂引用不入投影。
- **INV-22** 子航班集合变化必须使涉及的主航班在同一事务内推进 `STATE_VERSION` 并登记主航班事件;投影只进不退,版本不推进即被下游丢弃。
- **INV-23** Redis 投影写成功才算处理完成:写失败的消息不置终态、不写回填标记,保持未完成,下轮重新处理;自有 PG 已提交的业务结果不因此回滚(`US-05` AC4、`US-06` AC1)。
- **INV-24** Redis 航班投影只由本系统写入与移除;`GET /all/flights` 与网页客户端同源读 Redis;Redis 异常时报错,不返回空列表伪装成功(`US-12` AC1/AC2)。
- **INV-25** 处理记录清理:只删「终态且已回填」且超过保留期的记录;未完成的不删。保留期可配置(`US-11`)。
- **INV-26** 静态参考数据按(类别, 编号)保存,新消息覆盖旧记录;全量消息整体替换,增删改消息逐条处理;消息里字段为空表示「当前没有值」,不是删除(`US-13` AC1/AC3/AC4)。
- **INV-27** 一类参考数据校验不通过就不更新这一类,其他类照常处理;该类已有数据不动(`US-13` AC2)。
- **INV-28** 航班先写历史存储、确认成功后才从实时数据删除;写入失败下次重来,已写入的不重复写入;单个航班失败不影响其他航班;正在被消息处理的航班跳过、下轮再处理(`US-14` AC3/AC4;写者互斥见 `INV-18`)。
## 5. 声明边界
| 编号 | 主张 | 依赖 | 当前可否声明 | 挂起原因 |
|---|---|---|---|---|
| CLM-3 | 失败重处理与重复发现不产生重复业务副作用 | INV-20b、`G-FLOP-IDEMPOTENT` | **不可** | 逐类幂等矩阵未补全 |
| CLM-4 | 回填不会被短暂故障放弃:最终打标,或进入可对账的放弃清单 | INV-8、`C-5``C-8` | **可声明(有条件)** | 条件:`R` 之前不放弃;`MISSING_ROW` 立即放弃并告警;放弃行须经人工对账才可用于清除判定(`C-8` |
| CLM-6 | 单实例内严格 FIFO | PRE-5、INV-3 | **可**(限于单活动实例) | — |
| CLM-7 | 事件投递在同一 `FLID` 内保序 | INV-10、投递设计 | **可**(跨 `FLID` 不承诺) | 实现当前按目标级全序投递,收敛到按 `FLID` 属投递改造 |
| CLM-8 | 出站交付承诺只到「落信」 | `C-24``Q10` | **可**(仅落信语义) | 消费方已定(CIIMS adapter);ACK 列语义未确认 |
| CLM-9 | 处理标记延迟由调度周期决定 | — | **不可** | 扫描周期不等于完成时限;批次积压、单行超时与清理作业都会延长实际延迟 |
| CLM-10 | 容量量级假设(单实例、入站日消息量千级到万级、单报文 ≤ 10⁴ 字节) | — | **不可** | 未实测,无生产负载数据;解除条件:取得现役信箱日量、峰值与单报文上限后重估 |
## 6. 验证映射
每条不变量至少一条证据。测试名以仓库现状为准;新增测试按本表补位。本表只记录**验收口径与证据位置**,覆盖进展只在 Plane(ACM2)。
| 不变量 / 声明边界 | 场景 | 证据 / 测试 |
|---|---|---|
| INV-1 | 五事实互不替代:入队不引用标记、回填不引用投递、投递不引用回填 | 需接口级断言 |
| INV-2b | 谓词扫描与批次上限 | 只读「处理标记为空」的行、每批有上限;`InboxPollerTest`(随 `G-SCAN-PREDICATE` 改造重写) |
| INV-2b | 重复扫描、重启恢复 | 不重复登记、不重复处理、不丢记录 |
| INV-3 | 较小 ID 迟提交 | 迟发现的较小编号仍按编号序登记处理,不丢、不重复 |
| INV-3 | 队头失败、退避及作业竞争 | 消息不越队;到期后恢复;作业不使消息无限饥饿 |
| INV-6 | 投递失败后终态不变 | 需用例 |
| INV-7 | 回填四种结果 | 写入成功 / 早已标记(不覆盖、记成功)/ 信箱行不存在(立即放弃并告警,不得视为已标记)/ 暂时故障持续到 `R` 仍未打标(停止自动重试,可人工恢复) |
| INV-7 | `RECEIVED_AT` 为 NULL | 超期分支仍成立且不导致标记提前写入——判据是本地 `ENQUEUED_AT`,与库方时钟及 NULL 无关 |
| INV-8 | PG 提交失败、回填失败 | 事件、终态与回填意图一起回滚;已提交结果只补写标记,不重放业务;中间态永不补写 |
| INV-8 | 非业务型终态 | 不触碰航班表 / `MSG_EVENT`,只写 `PROC_STATE`,且终态与回填意图同语句生效 |
| INV-9 | 同身份多条记录、失败后重试、清理后重复 | 只产生一次有效业务处理,不把自身重试判为重复 |
| INV-10 | 投递确认丢失、批次失败、次数耗尽 | 允许可识别的重发、保持目标顺序、整批退避并保留死信 |
| INV-11b | 权威唯一 | 需断言信箱、Redis 投影、展示视图不成为写入或对账来源 |
| INV-12 / INV-13 | PG 事务失败、快照重复或迟到 | 整体回滚重试、不重复推进版本、不回退状态、不误删增量航班 |
| INV-12 | 运营日冲突 | 整包 `DEAD(PROTOCOL)`,既有状态与版本不变 |
| INV-14b | 增量未携带字段保留、显式清空才清除;集合按完整合并结果写入 | `FlightStateEngineTest`「flop merge retains absent scalars and collections」;`FdelAndAdftProcessorTest`「ADFT merge does not clear absent scalars」 |
| INV-14b | FLOP 逐类空标签语义(清除、撤销、集合清空)与「未携带不清空」的区分 | 逐类用例见 [implementation.md](implementation.md)「动态运行事件」;`G-FLOP-UNMAPPED``G-FLOP-SEMANTICS` |
| INV-15b | 快照缺席航班删除、未携带字段清除;增量不适用快照语义 | 新增用例(`G-SCHD-SNAPSHOT` |
| INV-16 | 外部副作用失败后本地结果不变 | 需用例 |
| INV-17b | 状态与事件同事务;终态与回填意图同事务且晚于 Redis 写成功;日计划分批 | 需真实 PG 用例 |
| INV-18 | 清理与处理并发 | `HistorySweepJobTest`(归档后被主泵更新的航班不删除、不发 tombstone)+ `HistorySweepPurgePgTest`(删除阶段失败时 tombstone 与删除整体回滚) |
| INV-19 | 整包协议拒绝(声明数不符、运营日冲突) | `DEAD(PROTOCOL)`,整包不落地、整体回滚、既有状态不变 |
| INV-21 | `MAFL` 投影与 `ACTIVE` 子航班集合一致(子航班删除后退出、自引用与悬挂引用不入、顺序确定) | `G-MAFL`:投影未实现 |
| INV-22 | 子航班新增、删除、`MAID` 迁移时主航班版本与事件 | `G-MAFL`:主/共享级联未实现 |
| INV-20b / CLM-3 | 同一消息失败重处理、重复发现 | 阻塞于逐类幂等矩阵(`G-FLOP-IDEMPOTENT` |
| INV-23 | Redis 写失败 | 消息保持未完成、不提前写标记;重处理收敛 |
| INV-24 | 同源读取与异常 | Redis 异常时报错、不返回空列表 |
| INV-25 | 清理谓词 | 只删「终态且已回填」超保留期的记录 |
| INV-26 / INV-27 | 参考数据覆盖 / 全量替换 / 空标签 / 逐类门控 | 需用例(`G-REF-DATA` |
| INV-28 | 历史先行 | 历史未确认成功删除 0 条;已写入不重复写入 |
| — | 请求超时、无匹配 RESP、时间单位不一致 | 不误用迟到应答、不提前完成请求 |
| — | stub 误配置、重复实例、停机中断 | 生产拒绝不安全启动,工作线程能正确退出 |
上表首列是**引用**`INV-x` 的定义见本文件「不变量」);同一行可覆盖多个 `INV`,例如 `INV-20b / CLM-3`
声明边界的证据指针:`CLM-4` 断言放弃行不写标记、不被当作已打标;`CLM-9` 由作业心跳与回填年龄指标提供观测(指标名见 [reference.md](reference.md)「指标与健康」),实际延迟仍需现场数据。
## 7. 当前已知偏差
本表是**偏差标记的唯一出处**:其他文档只在相应位置写 `G-NAME`,不解释、不记进度。偏差只写事实与受影响稳定 ID,不写负责人、日期、进度或 Plane 状态;闭合时在同一变更中删除本行与全仓 `G-NAME` 引用,关闭证据留在 Plane。
| 偏差 | 含义 | 影响 |
|---|---|---|
| `G-RESP-GUARD` | `RESP` 应答守卫未实现,当前与 `DNLD` 无差别进入快照写入 | 请求匹配闭环;`C-23` |
| `G-REQ-TRACK` | `REQ_TRACK` 无运行时协调器:出站适配、请求编码、超时与应答匹配未实现 | `US-09``C-24` |
| `G-FLOP-IDEMPOTENT` | SIS 25 类与现场延续的 7 类(靠桥、延误、计划机位等)尚无完整逐类幂等矩阵 | `INV-20b``CLM-3` |
| `G-MAFL` | 主航班 `MAFL` 派生投影及主/共享原子级联未实现(规则见 `INV-21`/`INV-22`);`MAFL` 不是 SIS/XML 入站字段 | 航班完整态;删除与重建 |
| `G-SRVT-VIPF` | SIS/XML 的 `SRVT``VIPF` 无界集合尚未映射到持久化明细;wire/domain 只保留出现事实与原始内容,不参与合并与投递(清空语义见 `Q13` | 航班完整态;无损字段保存 |
| `G-COMPAT-HTTP` | compat 入口尚未按 `US-02` 口径实现:请求体上限取值与失败响应样例未对拍(媒体类型集与成功/失败响应语义已定案) | `C-28``US-02` |
| `G-REQ-OPEN-UNIQUE` | `REQ_TRACK` 尚无约束开放态 `(REQ_TYPE, OPERATION_DAY, SENDER)` 唯一性的部分索引 | `US-09``G-REQ-TRACK` |
| `G-REQ-TRACK-RETENTION` | `REQ_TRACK` 关闭态行(`DONE`/`EXPIRED`)的保留期与清除作业未定义 | 自有 PG 无界增长;`US-09` |
| `G-FLIGHT-HIST-RETENTION` | 航班历史存储(外部)的保留期与容量上限未定义 | `INV-28`;实时数据物理清除后历史存储是唯一副本 |
| `G-FLOP-UNMAPPED` | [XSD](legacy/unisysaodbsis.xsd)「FLOP 元素」的 `FFID``UNCL``CKOP``GTOP``CKCL``BDOP``LCTM``BDCL``FRET``FDIV``FLAB``RUNW``PXNO``FLBG``CKPB``BDPB` 未解码;`CHDT.CCLS/CTYP` 被错误写成 `CHCLS/CHTYP`,均会静默丢失。其中 `FRET``FDIV``BDPB` 在 legacy 有对应处理 | `US-05`;无损字段保存 |
| `G-FLOP-SEMANTICS` | FLOP 未按 SIS 25 类建立 `STYP` 白名单;`ROUT` 未按方向截取至 4 条且仍保存 `SCAT`/`SCDT`;BOTM/LACL 未同步设置或重置运行状态;除 FDEL 外,已删除航班仍会被合并、增版并发事件 | `US-05``INV-14b``INV-20b` |
| `G-REF-DATA` | SIS 静态参考数据处理(`SIS:3.1``SIS:3.14`)未实现;当前按「合法但不支持」跳过并回填(`US-03` AC2),独立参考数据表与 admin-api 直读未落地 | `US-13``US-03` |
| `G-SCAN-PREDICATE` | 收报仍按持久水位 ID 区间扫描(含空洞老化与切流播种),未达「处理标记为空」谓词口径 | `US-01``INV-2b` |
| `G-REDIS-PROJECTION` | 无任何 Redis 投影写/移除路径:航班动态写入、删除移除、快照刷新、查询读取均未实现 | `US-05``US-06``US-07``US-12` |
| `G-SCHD-SNAPSHOT` | 日计划快照未达 `US-07` 口径:缺席航班不删除、未携带字段不清除、整包单事务(需求要求分批、每批一个事务) | `INV-15b``INV-17b` |
| `G-PROC-CLEANUP` | 处理记录到期清理作业未实现(归档链随 `US-11` 口径废弃) | `US-11``INV-25` |
## 8. 待确认事项台账
| 编号 | 事项 | 当前假定 | 阻塞 | 状态 |
|---|---|---|---|---|
| Q1 | 权威存储(内部方向)与生产库选型 | 自有 PG 单库权威 + 无损明细;生产环境用 PostgreSQL 还是 Oracle 11g 未定,Oracle 适配验证通过前不构成支持承诺 | 生产部署验收 | 已定案(内部),生产库待定 |
| Q2 | 信箱 ID 分配顺序即到达顺序;ID 空间不复位、不复用 | — | 到达顺序声称(`US-01` AC3 | 未确认 |
| Q3 | HTTP 契约:请求体上限取值、失败响应样例 | 上限暂定 10MB(`C-28` | 兼容入口验收 | 未确认 |
| Q4 | Kafka 载荷与去重标识 | 主题/粒度/保序已按 `US-08` 定案:`msg` 发单条变更、`schd` 定时批量发最新状态、key=`FLID` | 投递契约 | 未确认 |
| Q5 | 请求匹配:回显字段可靠性与降级匹配 | `RQFD` 60 秒 / `RQRD` 30 秒超时 | 请求跟踪闭环 | 未确认 |
| Q7 | 处理标记值集与写权限、原文保留期、处理时间语义 | 写入 `PROCESSED` | 回填值集、保留期下界 | 未确认 |
| Q8 | 逐类覆盖:SIS 未定义但现场会发的 7 类(靠桥、延误、计划机位等)的报文形态、除 FDEL 外目标航班不存在/已删除时的逐类终态、BOTM/LACL 运行状态的落点 | 航班动态的字段与空标签规则以 `SIS:3.19``SIS:3.43` 为准(`US-05` AC1 定案);静态参考数据以 `SIS:3.1``SIS:3.14` 为准(`US-13`);legacy 7 类按现有处理逻辑延续(`US-05` AC1 定案) | 逐类幂等矩阵与 golden(`G-FLOP-SEMANTICS``G-FLOP-IDEMPOTENT``G-REF-DATA` | 未确认(不阻塞 `US-13` 验收) |
| Q9 | 清除执行方与 DDL 授权、方案 A/B 选型、分区能力 | 首选方案 A | `R_keep` 与清除边界 | 未确认 |
| Q10 | 出站 ACK 列语义、出站行清理与去重契约 | — | 出站信箱 | 未确认 |
| Q11 | 上游 `SEQN` 重置周期与业务身份的日期边界 | 不含日期边界 | 身份算法 | 未确认 |
| Q13 | 日计划缺失可选字段的删除语义 | 结论(2026-09-14):未携带字段视为 AODB 已删除该值,本地同步清除(`C-26` | — | 已定案 |
| Q14 | 主/共享删除顺序与 EROR 回报义务 | 结论(2026-09-14):幂等原子级联、不回发 EROR(`C-25` | — | 已定案 |
| Q15 | 上游是否会以同一业务身份改发正文(决定是否需要区分「重复」与「改发」) | 假定期望不可变(`C-4` | 身份去重语义 | 未确认 |
| Q16 | `FLID` 重用语义(决定版本是否按 incarnation 作用域) | 假定不复用(`C-21` | 事件合并与 tombstone | 未确认 |
Q 的答复只在本表就地更新(补「结论」与日期),并触发 [README.md](README.md)「维护清单」的落地 4 步;不另开文件。
## 9. 契约数值
| 量 | 定义处 | 约束 |
|---|---|---|
| `R_keep` | `C-7` | `R_keep ≥ max(审计期限, 回填重试上限)`;原文保留期下界(重放不在交付范围) |
| `R` | [reference.md](reference.md) `PARAM:msgx.pipeline.overdue-backfill` | `R ≤ R_keep`;只决定强补写与放弃期限 |
| 去重记忆期 | `INV-9` | = 处理记录保留期(`US-11`);期内同身份去重成立,期满后同身份消息按新消息处理 |
| 回填放弃清单可见期 | `C-16` | ≥ `R_keep`;否则库方清除缺 `C-8` 依据 |