Files
th-hotel-simple/docs/project/requirements/M002-v4-agent-callback-field-contract.md
2026-07-19 01:44:32 +07:00

758 lines
33 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.

# M002 V4 Agent 回调字段契约
## 文档信息
| 项目 | 内容 |
| --- | --- |
| 文档版本 | 1.5 |
| 日期 | 2026-07-19 |
| 状态 | 当前 V4 字段基线;后端已完成 CP1 入站解析基线、CP2 多卡模型设计、CP3 持久化基线、CP4 入站写入新模型和 CP5 查询接口V4 写接口仍需后续 checkpoint |
| 适用范围 | 0718 业务基线下Agent → Adapter / MCP → 信息系统的业务回调字段 |
| 不适用范围 | 数据库表设计、前端视觉细节、真实 PMS API、技术失败后台重试、旧 M002 V3 数据兼容 |
## 1. 文档定位
本文把 2026-07-18 导入的业务基线、Agent 回调问题答复、草案审查答复和剩余 10 项确认回复,整理为 M002 V4 的 Agent 回调字段契约。
本契约用于后续 M002 V4 主流程设计、后端领域建模、前端页面模型、Adapter / MCP Schema 对齐和 SuperAgent 联调。当前后端已按本文完成 V4 入站解析基线:能识别 V4 包、校验关键契约、保存 AI transition / 任务卡原始 payload并把可映射的六类 event 先接入现有订单任务链路。
V4 订单任务与多卡领域模型的 CP2 设计已经单独落到 `M002-v4-order-task-card-domain-model-cp2.md`。截至 CP5表结构、Entity、Mapper、Repository 基线已经实现SuperAgent V4 入站已经能写入 V4 订单任务、来源邮件展示卡、Basic Information 卡、业务卡和 S10/S99 来源通知V4 工作台、订单任务列表 / 详情和来源通知详情查询接口已实现,卡片确认、复核和来源通知 ack 写接口仍未实现。
当前已确认开发阶段数据可以清空,因此 M002 V4 后续可以按新模型重建,不要求兼容旧任务数据、旧草稿、旧 OPERA 模拟、旧 `S000/S999`、旧 Fallback 或旧 `case_keys`
## 2. 输入资料与优先级
| 文档 | 用途 |
| --- | --- |
| `docs/import/20260718/0718给黄哥/01-预订任务信息系统业务需求说明书.md` | 0718 业务权威基线 |
| `docs/import/20260718/0718给黄哥/02-业务字段与卡片规则矩阵.md` | 业务卡字段、展示和确认规则 |
| `docs/import/20260718/0718给黄哥/03-业务验收场景清单.md` | 验收场景 |
| `docs/import/20260718/0718业务基线-Agent回调问题答复.md` | 第一版 Agent 目标回调结构说明 |
| `docs/import/20260718/0718-M002-V4-Agent回调草案审查与最新答复.md` | 对 V4 草案的最新业务修正;与上一份答复冲突时以本文为准 |
| `docs/import/20260718/0718-V4剩余10项确认回复.md` | 对剩余技术 key、校验和运行边界的确认 |
如果本文与早期 M002 V3、0711 / 0712 P0、旧草案或历史聊天记录冲突M002 V4 字段和业务语义以本文为准。
## 3. 总体结构
一封当前邮件对应一个结果包。
普通业务包:
```json
{
"route_code": null,
"source_message": {},
"order_contexts": [],
"message_events": []
}
```
纯通知包:
```json
{
"route_code": "S10",
"source_message": {},
"order_contexts": [],
"message_events": []
}
```
核心关系:
```text
source_message
-> 提供当前邮件展示卡和附件资源
order_contexts[]
-> 每个 order_ref 一项,承载该订单任务的 Basic Information
message_events[]
-> 每个具体业务 Event 生成一张对应业务任务卡
source_message.source_message_id + order_ref
-> 一笔订单任务
target_order
-> 用于信息系统查单和绑定订单,不用于当前包内归组
```
## 4. 冻结 key
V4 正式采用并冻结以下 key
| key | 中文说明 |
| --- | --- |
| `route_code` | 包级路由。普通业务为 `null`,纯通知为 `S10``S99` |
| `source_message` | 当前触发邮件的包级来源事实,只出现一次 |
| `order_contexts` | 订单级上下文集合,每个 `order_ref` 一项 |
| `message_events` | 业务事件数组,承载六类 Event |
| `order_ref` | 当前结果包内订单引用,用于聚合同一订单,不是 PMS 键或系统 ID |
| `target_order` | 目标订单定位信息,用于信息系统查单和绑定订单 |
| `attachment_ids` | Payment 关联包级附件的 ID 数组 |
SuperAgent、Adapter、MCP Schema 和信息系统最终必须使用完全相同的字段名与嵌套位置。
## 5. source_message
### 5.1 结构
```json
{
"source_message_id": "string",
"conversation_id": "string | null",
"subject": "string | null",
"sender": "string | null",
"sent_at": "2026-07-18T02:10:00Z",
"body": "string | null",
"body_content_type": "text/plain | text/html",
"attachments": []
}
```
### 5.2 字段规则
| 字段 | 必需 | 中文说明 |
| --- | --- | --- |
| `source_message_id` | 是 | 当前触发邮件的稳定唯一 ID本项目映射为 SourceMessage Inbox 的 `external_message_id` |
| `conversation_id` | 否 | 当前邮件会话 ID完整历史线程由信息系统按该值查询 |
| `subject` | 是,可为 `null` | 邮件主题 |
| `sender` | 是,可为 `null` | 邮件监听提供的单一发件人值,不拆 display / address |
| `sent_at` | 是,可为 `null` | 邮件发送时间,统一 UTC ISO-8601 |
| `body` | 是,可为 `null` | 当前邮件单一原文Agent 原样转发,不清洗、摘要、翻译、重排或改写 |
| `body_content_type` | 是 | 正文格式,取值 `text/plain``text/html` |
| `attachments` | 是 | 包级附件数组 |
`received_at` 不是当前页面和业务处理必需字段。如基础设施需要,可作为内部技术元数据保存,不作为业务必传字段。
`body_content_type` 按当前项目建议由 AgentBus / 邮件监听层或 Adapter 提供Debug EML 和 AgentBus 入库也应保存或派生该字段。信息系统根据该字段选择纯文本转义或 HTML 安全渲染,但不得改写保存的原始 `body`
## 6. attachments
### 6.1 结构
```json
{
"id": "att-1",
"name": "payment-slip.jpg",
"content_type": "image/jpeg",
"url": "https://upstream-storage/...",
"size": 251524
}
```
### 6.2 字段规则
| 字段 | 必需 | 中文说明 |
| --- | --- | --- |
| `id` | 是 | 包内稳定附件引用 |
| `name` | 是 | 原始文件名 |
| `content_type` | 是 | MIME 类型 |
| `url` | 是 | 上游邮件监听或文件存储层提供的可访问地址 |
| `size` | 否 | 上游有值时原样传递 |
URL 由上游邮件监听或文件存储层提供。Agent 只原样转发,不生成、拼接、刷新或签发 URL。
Payment 只按 `attachment_ids[]` 引用附件,不在 Event 内复制文件名、类型、URL 或完整附件对象。
## 7. order_contexts
### 7.1 结构
```json
{
"order_ref": "order-1",
"basic_information": {
"account_code": "ACCOUNT_CODE",
"manual_review": null
}
}
```
### 7.2 规则
- 一笔订单只有一份 Basic Information。
- Basic Information 跟随订单,不跟随具体 Event。
- Basic Information 不是 `event_type`,但它是订单任务中的一张独立可确认、独立锁定任务卡。
- 同一订单下即使同时有 Update、Trace、Rooming List、Payment也只显示一张 Basic Information 卡。
- 一封邮件可能包含多笔订单,因此 Basic Information 不能放成整个结果包唯一对象。
- 每个非 S10 订单至少有一个非空 `order_ref`,并且在 `order_contexts[]` 中只能出现一次。
- 每个具体 Event 必须引用一个已存在的 `order_ref`
### 7.3 Basic Information 字段
| 字段 | 必需 | 中文说明 |
| --- | --- | --- |
| `account_code` | 是,可为 `null` | 信息系统 Account 目录中的稳定 code不是自由文本或显示名称 |
| `manual_review` | 是 | `null``true`;为 `true``account_code` 必须存在可解释的未解决状态,例如 `null` |
Market 和 Source 不由 Agent 输出,由信息系统根据订单级 `account_code` 从目录派生。用户只能从信息系统已有 Account、Market、Source 中受控改选;不存在 Manual 或自由输入。
Agent 给出非空 `account_code`,但信息系统运行时目录不存在该值时,属于系统目录 / 契约校验问题Basic Information 卡阻止确认并显示字段错误,但不得反向篡改 Agent 原始 `manual_review`
不同 `order_ref` 可以对应不同 Account。
## 8. message_events 公共字段
### 8.1 结构
```json
{
"order_ref": "order-1",
"event_type": "UPDATE_BOOKING",
"target_order": {
"booking_type": "GROUP",
"locator_type": "GROUP_CODE",
"locator_value": "LLTQ260510QVIPA"
},
"manual_review": null
}
```
### 8.2 公共字段规则
| 字段 | 必需 | 中文说明 |
| --- | --- | --- |
| `order_ref` | 是 | 当前包内订单引用,必须存在于 `order_contexts[]` |
| `event_type` | 是 | 业务事件类型 |
| `target_order` | 是 | 目标订单定位信息,用于信息系统查单和绑定订单 |
| `manual_review` | 是 | `null``true`;只作用于当前 Event 对应任务卡 |
以下字段不属于 Event 公共字段:
- `account_code`:已改为订单级 Basic Information。
- `payload`V4 直接使用各 Event 的专属业务字段,不增加通用 payload 层。
- `evidence`:不是信息系统页面业务必传。
- `event_index`:数组顺序不承载业务顺序,页面顺序由信息系统按固定卡片规则决定。
- `event_id`:如 transport / 幂等需要,另由技术契约增加,不能代替 `order_ref`
## 9. event_type
V4 新数据只允许以下六种:
```text
NEW_BOOKING
UPDATE_BOOKING
CANCEL_BOOKING
TRACE_RESERVATION_NOTES
ROOMING_LIST
PAYMENT
```
| `event_type` | 对应卡片 | 中文说明 |
| --- | --- | --- |
| `NEW_BOOKING` | 房间信息 | 新建预订 |
| `UPDATE_BOOKING` | 房间信息 | 修改预订 |
| `CANCEL_BOOKING` | 房间信息 | 整单取消 |
| `TRACE_RESERVATION_NOTES` | Trace | 普通备注 / 加床备注 |
| `ROOMING_LIST` | Rooming List | 任务详情内嵌 Rooming List |
| `PAYMENT` | Payment | 付款凭证 |
Basic Information 不是 Event。邮件展示卡不是 Event`source_message` 固定生成。
S10/S99 是包级来源通知路由不属于上述业务枚举。S10 表示纯信息类邮件S99 表示无法形成业务素材包;两者都不创建订单或业务卡。
Fallback、`Need Manual Review`、独立 Voucher、旧 Payment Evidence、Voucher Received 均不再作为新 Agent 输出。
## 10. target_order
### 10.1 结构
```json
{
"booking_type": "GROUP",
"locator_type": "GROUP_CODE",
"locator_value": "LLTQ260510QVIPA"
}
```
### 10.2 合法组合
| 场景 | `booking_type` | `locator_type` | `locator_value` |
| --- | --- | --- | --- |
| Group 的所有业务 | `GROUP` | `GROUP_CODE` | Group Code即 Block Name |
| Fit New以及与该 New 同包同目标的 Trace | `FIT` | `BOOKING_CODE` | Booking Code |
| 当前无 PMS API、尚无真实 Confirmation Number 的 Fit 后续业务 | `FIT` | `BOOKING_CODE` | 查询信息系统本地订单投影 |
| 已取得真实 Confirmation Number 的 Fit 后续业务 | `FIT` | `CONFIRMATION_NUMBER` | PMS Confirmation Number |
### 10.3 规则
- 当前包内同订单归组使用 `order_ref`,不是使用相同 `target_order` 或相同 `null`
- `target_order` 用于信息系统查单和绑定订单。
- 同一 `order_ref` 下的非空 `target_order` 必须一致。
- 定位值未解决时保留原 Event未知字段为 `null`Event 的 `manual_review=true`
- Agent 能判断多个 Event 属于同单但定位未解决时,仍使用相同 `order_ref`
- Agent 连是否同单都无法判断时,使用不同 `order_ref`,不能把相同 `null` 合并。
- 不输出旧 `case_keys`、定位候选数组、原因码或 `missing_fields[]`
- AMEND GROUP CODE 统一走 S10不形成 Update Event。
## 11. NEW_BOOKING
### 11.1 结构
```json
{
"order_ref": "order-1",
"event_type": "NEW_BOOKING",
"target_order": {
"booking_type": "GROUP",
"locator_type": "GROUP_CODE",
"locator_value": "GROUP-CODE"
},
"arrival_date": "2026-07-26",
"departure_date": "2026-07-29",
"rate_code": "RATE_CODE",
"booking_scenario": "STANDARD",
"room_items": [
{
"room_type_code": "TWN",
"room_count": 1
}
],
"manual_review": null
}
```
Fit 条件字段:
```json
{
"guest_name": "REAL GUEST NAME | null"
}
```
### 11.2 字段规则
| 字段 | 适用 | 必需 | 中文说明 |
| --- | --- | --- | --- |
| `arrival_date` | Group / Fit | 是,可为 `null` | 入住日期,酒店本地日期 |
| `departure_date` | Group / Fit | 是,可为 `null` | 离店日期,酒店本地日期 |
| `rate_code` | Group / Fit | 是,可为 `null` | 订单级 Rate Code |
| `room_items[]` | Group / Fit | 是 | 完整房型清单 |
| `room_items[].room_type_code` | Group / Fit | 是,可为 `null` | 受控 RoomType code |
| `room_items[].room_count` | Group / Fit | 是 | 房量,正整数 |
| `booking_scenario` | Group | 是 | `STANDARD``PROPOSAL` |
| `guest_name` | Fit | 否,可为 `null` | Fit 真实客人姓名;首封无真实姓名时可以为空 |
### 11.3 派生和禁止字段
- Group Code 已在 `target_order.locator_value`,同时作为 Block Name。
- Fit Booking Code 已在 `target_order.locator_value`
- Agent 不输出 `booking_name`、独立 `booking_code`、Nights、Breakfast、Group Booking Status、Adult、Block ID 或 Confirmation Number。
- `proposal` 不再使用布尔字段,改为 `booking_scenario=STANDARD | PROPOSAL`
- Adult 由信息系统按 RoomType 映射派生。
- `room_items=[]` 只能表示已识别 New 但完整房型清单未解决,并必须 `manual_review=true`
## 12. UPDATE_BOOKING
### 12.1 结构
```json
{
"order_ref": "order-1",
"event_type": "UPDATE_BOOKING",
"target_order": {
"booking_type": "GROUP",
"locator_type": "GROUP_CODE",
"locator_value": "GROUP-CODE"
},
"after": {
"arrival_date": "2026-07-27",
"departure_date": "2026-07-30",
"room_items": [
{
"room_type_code": "TWN",
"room_count": 3
}
]
},
"manual_review": null
}
```
### 12.2 after 三态和字段规则
`after` 是稀疏对象:字段缺省表示本次不修改。
| 字段 | 语义 |
| --- | --- |
| `after.guest_name` | Fit Name 更新 |
| `after.arrival_date` | 修改后入住日期 |
| `after.departure_date` | 修改后离店日期 |
| `after.room_items` 不存在 | 本次邮件没有要求修改房型或房量 |
| `after.room_items=null` | 已识别本次涉及房型或房量修改,但无法形成修改后的完整房型清单;必须同时 `manual_review=true` |
| `after.room_items=[...]` | 修改后的完整房型清单,不是只输出变化行 |
### 12.3 规则
- 字段存在但为 `null`,表示已识别要改该字段、但目标值未解决,同时 `manual_review=true``null` 不表示清空。
- 只要修改涉及房型或房量,`after.room_items[]` 必须是修改后的完整房型清单。
- 不使用空数组表达“无法形成完整房型清单”。
- 如果修改后整笔订单不再保留任何房间,应按整单 `CANCEL_BOOKING` 处理,而不是提交空的 Update 房型清单。
- Rate Code 不允许出现在 Update。若 Agent 仍输出,按业务契约错误处理,不能静默忽略后继续执行。
- Before、原订单和完整最新订单由信息系统查单后生成不由 Agent 输出。
## 13. CANCEL_BOOKING
### 13.1 结构
```json
{
"order_ref": "order-1",
"event_type": "CANCEL_BOOKING",
"target_order": {
"booking_type": "GROUP",
"locator_type": "GROUP_CODE",
"locator_value": "GROUP-CODE"
},
"manual_review": null
}
```
### 13.2 规则
- `CANCEL_BOOKING` 本身已经表示整单取消。
- 不输出 `cancel_scope``cancel_reason``after` 或当前订单快照。
- 减少房量、删除房型、修改日期或修改 Fit Name 属于 Update不是 Cancel。
- 当前订单快照由信息系统查单后只读展示。
## 14. TRACE_RESERVATION_NOTES
### 14.1 结构
```json
{
"order_ref": "order-1",
"event_type": "TRACE_RESERVATION_NOTES",
"target_order": {
"booking_type": "GROUP",
"locator_type": "GROUP_CODE",
"locator_value": "GROUP-CODE"
},
"trace_items": [
{
"item_type": "GENERAL",
"text": "HONEYMOON SETUP",
"department_code": "FO"
},
{
"item_type": "EXTRA_BED",
"target_room_type_code": "TWN",
"extra_bed_room_count": 1,
"department_code": "FO+HSK"
}
],
"manual_review": null
}
```
### 14.2 字段规则
| 字段 | 适用 | 必需 | 中文说明 |
| --- | --- | --- | --- |
| `trace_items[]` | Trace | 是 | 同一订单一张 Trace 卡,卡内多条事项 |
| `item_type` | Trace item | 是 | `GENERAL``EXTRA_BED` |
| `text` | GENERAL | 是,可为 `null` | 普通备注内容 |
| `department_code` | GENERAL / EXTRA_BED | 是 | 信息系统受控部门或组合部门 code |
| `target_room_type_code` | EXTRA_BED | 是,可为 `null` | 加床目标房型 |
| `extra_bed_room_count` | EXTRA_BED | 是 | 加床房间数量 |
### 14.3 规则
- EXTRA_BED 不输出自由 `content`;信息系统固定显示 `SET EXTRA BED`
- EXTRA_BED 不输出 `adult_after_extra_bed`;信息系统按当前 / 基础 Adult +1 计算,页面确认前允许用户纠正。
- Department code 由 Agent 必传,值来自信息系统维护的受控部门目录或组合目录。
- 加床目标房型不在当前订单时Trace 卡不能确认,并提示用户核对目标房型和订单关联。
- 只有订单定位本身不可信时,才触发共享查单门槛阻断整个订单上下文。
## 15. ROOMING_LIST
### 15.1 结构
```json
{
"order_ref": "order-1",
"event_type": "ROOMING_LIST",
"target_order": {
"booking_type": "GROUP",
"locator_type": "GROUP_CODE",
"locator_value": "GROUP-CODE"
},
"manual_review": null
}
```
### 15.2 规则
- 只适用于 Group。
- 当前 Agent 只需识别这是 Rooming List 任务。
- 不输出 `rows[]`、逐人名单、同住分组、18 列、Excel 或 PMS 导入参数。
- 当前也不要求 Rooming List Event 单独输出 `attachment_ids[]`
- 原附件已经在包级 `source_message.attachments[]`,只在邮件展示卡查看。
- 页面固定展示 12 个必填字段表头的标准表格示意,当前内容不代表附件已经真实转换。
- 未来取得 PMS API 后,按真实接口重新冻结住客与执行参数,不直接恢复历史草案中的 `rows[]`
## 16. PAYMENT
### 16.1 结构
```json
{
"order_ref": "order-1",
"event_type": "PAYMENT",
"target_order": {
"booking_type": "GROUP",
"locator_type": "GROUP_CODE",
"locator_value": "GROUP-CODE"
},
"attachment_ids": ["att-1", "att-2"],
"manual_review": null
}
```
### 16.2 规则
- `attachment_ids[]` 至少一项。
- ID 不重复。
- 每个 ID 都必须存在于同包 `source_message.attachments[]`
- 每个 ID 必须属于当前订单的付款凭证。
- 一笔订单多份凭证放在同一个 Payment Event。
- `attachment_ids[]` 没有业务顺序。
- Payment 不输出 `account_code`、金额、付款日期、付款人、交易号、银行账号、付款状态、Department 或完整附件对象。
没有任何凭证附件时,不能创建正常的空 Payment 卡:
- 来源附件存在,但 Agent 没有关联任何 IDAgent / Adapter 契约错误。
- 来源本身没有可用于 Payment 卡的付款凭证:不形成正常 Payment按 S10 展示原邮件。
- 附件 metadata 存在但 URL 无法读取:附件或存储技术异常。
## 17. manual_review
### 17.1 合法值
`manual_review` 只允许:
```json
null
```
或:
```json
true
```
正常数据为 `null`,不使用 `false`
### 17.2 校验规则
- Event 的人工复核只属于该 Event 对应任务卡。
- Basic Information 的人工复核放在订单级 `basic_information.manual_review`,只属于 Basic Information 卡。
- 未解决值放在原业务字段位置,例如 `rate_code=null``room_type_code=null``account_code=null`
- `manual_review=true` 时,当前 Basic Information 或 Event 中必须存在至少一个由该 Schema 允许的未解决标记。
- 未解决标记可以是特定可空字段、被允许的空清单或不完整 item。
- 来源冲突时,把无法可靠决定的原业务字段置为 `null`
- 不能笼统认为任何空数组都能解释 `manual_review=true`
- 所有字段完整、合法且通过目录校验,却仍输出 `manual_review=true`,属于 Agent / Adapter 契约异常。
不增加以下字段:
- `manual_review_info`
- `missing_fields[]`
- `reason_code`
- 字段路径
- 候选值
- 复核说明对象
具体字段错误路径、错误码和页面提示由信息系统根据 Schema、目录和业务规则生成。
## 18. S10/S99 来源通知
### 18.1 结构
```json
{
"route_code": "S10",
"source_message": {},
"order_contexts": [],
"message_events": []
}
```
### 18.2 规则
- 只显示邮件展示卡。
- 不显示 Basic Information、房间信息或其他业务卡。
- 不需要 `order_ref``target_order`、Account 或业务字段。
- 采用来源通知模型:任务列表 / 工作台展示,点击进入纯通知详情页,不挂隐藏技术订单。
- 不创建订单、不进入订单列表、不参与订单阻塞也不支持编辑、复核、OPERA 或人工终止。
- 用户点击“确认”后任务完成。
- 不提供人工终止。
- 不调用 PMS不修改订单。
- S10/S99 第一版只表达来源通知类型,不输出 Fallback、原因码、通知说明或 `Need Manual Review`
## 19. 技术异常
下列情况不生成酒店用户可见任务,也不转换成 S10 或人工复核:
- 非法 JSON。
- 输出不符合 Schema。
- Event 引用了不存在的 `order_ref`
- 同一 `order_ref` 下出现冲突的非空 `target_order`
- Rate Code 出现在 Update。
- `manual_review=true` 但没有任何可识别的未解决字段。
- Adapter 转换失败。
- MCP 提交失败。
- Agent / Skill 执行异常。
- 附件 metadata 存在但存储 URL 无法读取。
技术失败不属于酒店用户任务。后台 debug、告警和技术重试接口属于技术运维需求不进入本次业务回调也不在酒店用户任务卡上增加“重试”。
当前后端实现口径:
- 如果 V4 包级结构不符合契约,但 `source_message.source_message_id` 能按 SourceMessage Inbox 的 `external_message_id` 定位到邮件,后端会创建 AI batch并写入一条 `catalog_code=M002V4``system_process_category=ADAPTER_CONTRACT_ERROR` 的 transition不创建订单、任务或酒店用户可处理卡。
- 如果 `source_message.source_message_id` 缺失、无法解析或无法定位 SourceMessage后端仍返回明确请求错误不创建 AI batch / transition。
- 单个 `message_events[i]` 的契约错误只影响该 event同包其它合法 event 继续按数组顺序处理。
- 普通 V4 业务包中,只有至少有一个合法业务 event 的 `order_ref` 会创建 V4 订单任务、来源邮件展示卡、Basic Information 卡和对应业务卡;全包只有契约错误 event 时不创建 V4 订单任务或用户可处理卡。
- V4 `route_code=S10/S99` 会写入 `workflow_reservation_v4_source_notification`,不再创建隐藏技术订单或旧 `workflow_reservation_task`;旧 V3 S10/S99 和旧文本 S000/S999 仍保留历史兼容链路。
当前项目可以保留 `platform_superagent_dispatch_run` 或同类技术运行记录作为主链路技术状态载体,后续另行设计查询、告警、超时和重试能力。
## 20. 受控 code 目录
Account、RoomType、RateCode、Department 的目录由信息系统或其主数据服务统一维护,并作为唯一事实源。
规则:
- SuperAgent 只能输出目录中已有的稳定 code。
- 不允许输出自由文本或自行创造 code。
- Agent 无法可靠匹配时,按对应业务字段的未解决规则处理。
- Agent 输出非空 code、但信息系统目录不存在该值时属于目录校验或契约问题。
- Market 和 Source 由信息系统根据订单级 `account_code` 派生,不由 Agent 输出。
当前项目接受“SuperAgent 确定后把目录给本系统”的落地方式。第一阶段可以先以固定种子目录或版本化目录快照对齐;后续如需在线查询或目录同步接口,再另开需求。
## 21. 后端 V4 建模建议
后端 V4 可以按以下聚合模型实现:
```text
AI 回调包
-> 按 source_message.source_message_id 反查 SourceMessage Inbox external_message_id
-> 保存 AI Batch / 原始 payload
-> 校验 order_contexts[] 和 message_events[]
-> 按 source_message_id + order_ref 创建订单任务
-> 每个 order_ref 创建一张 Basic Information 卡
-> 每个 Event 创建一张业务卡
-> 固定补邮件展示卡
-> target_order 用于查单和绑定本地订单投影
```
建议新增或调整模型概念:
| 概念 | 中文说明 |
| --- | --- |
| 订单任务 | 同一来源邮件 + 同一 `order_ref` 的聚合容器 |
| 任务卡 | 独立确认、独立锁定的业务卡 |
| 本地订单投影 | 当前无 PMS API 阶段,用于保存 New / Update / Cancel 后的信息系统内最新订单状态 |
| 技术失败记录 | Agent / Adapter / MCP 技术异常,不进用户任务列表 |
## 22. 已确认技术口径
| 项目 | 当前口径 |
| --- | --- |
| V4 key | `route_code``source_message``order_contexts``message_events``order_ref``target_order``attachment_ids` |
| `source_message_id` 映射 | 本项目按 SourceMessage Inbox 的 `external_message_id` 处理 |
| 时间格式 | UTC ISO-8601例如 `2026-07-18T02:10:00Z` |
| 正文格式 | 单一 `body` + `body_content_type=text/plain/text/html` |
| code 目录 | 信息系统主数据是唯一事实源,目录同步方式后置 |
| 技术异常 channel | 需要独立建设,不进入酒店用户任务体系;当前先保留设计空间 |
| Payment 附件 | 正常 Payment 必须 `attachment_ids.length > 0` |
| `manual_review` validator | 按各对象条件 Schema 校验,必须能由可识别未解决字段解释 |
| Update room_items | 不存在 / `null` / 数组三态 |
| Fit Booking Code 临时定位 | 当前无 Confirmation Number 时可用 Booking Code 查本地订单投影;第一版不建立 ACTIVE 唯一约束,匹配多条进入人工复核 |
| V4 前端资源路径 | 新开 `/api/reservation/order-tasks/**`,不扩展旧 `/api/reservation/tasks/**` 作为 V4 主入口 |
| Basic Information 前置 | Basic Information 必须先确认;业务卡之间第一版不强制逐张顺序确认 |
| Account 目录 | 第一版使用信息系统后端固定种子数据 |
## 23. 后续仍需技术对齐
以下事项不会改变 V4 页面业务含义,但会影响联调和实现细节:
1. SuperAgent、Adapter、MCP Schema 和信息系统 DTO 使用同一份 V4 Schema。
2. `body_content_type` 的来源是 AgentBus / 邮件监听层还是 Adapter 派生。
3. `dispatch_run_id`、超时、错误 channel 和技术失败查询入口如何落地。
4. Account、RoomType、RateCode、Department 目录如何提供给 SuperAgent以及目录版本如何管理。
5. 如需 `event_id` 或幂等键,应作为 transport 字段设计,不作为业务页面字段。
## 24. 当前开发结论
- 0718 业务基线覆盖 M002 V3 的任务级草稿、READY、OPERA 模拟、Fallback、S99 和旧 Need Manual Review 页面语义。
- 新数据按 `S10/S99` 表达来源通知;两者都采用同一来源通知模型。
- 用户可见任务按订单任务 + 多卡建模。
- 普通业务邮件的来源邮件展示卡只读展示,不需要用户确认。
- S10/S99 因为没有业务卡,邮件展示卡需要确认按钮,用于记录已读 / 已处理。
- Basic Information 必须先确认;其它业务卡第一版可以独立确认,不强制逐张顺序确认。
- 每张业务卡独立确认、确认后永久锁定。
- 不保存草稿。
- 当前无 PMS API不生成 OPERA 模拟操作和 PMS 成功语义。
- 技术异常不创建用户可见任务。
- 开发阶段不兼容老数据,允许清空旧任务相关数据后迁移。
## 25. 后端 CP1 已落地范围
2026-07-18 后端已完成 M002 V4 入站解析与数据模型基线,当前代码支持:
- `POST /api/integrations/superagent/task-results` 接收 V4 JSON 包:`route_code``source_message``order_contexts[]``message_events[]`
- `source_message.source_message_id` 按 SourceMessage Inbox 的 `external_message_id` 定位当前邮件SuperAgent 不传内部数据库 ID。
- V4 `route_code=S10/S99` 写入 `workflow_reservation_v4_source_notification` 来源通知模型;旧 `SOURCE_MESSAGE_ONLY` 只读特殊任务仅保留给 V3 S10/S99 和旧 S000/S999 兼容数据。
- 普通业务包要求 `route_code=null`,并按 `message_events[]` 数组顺序处理。
- 第一版识别六类 `event_type``NEW_BOOKING``UPDATE_BOOKING``CANCEL_BOOKING``TRACE_RESERVATION_NOTES``ROOMING_LIST``PAYMENT`
- 能映射到现有稳定任务卡的 event 会创建业务任务,并在 `ai_payload_json` 中保存 `v4_source_message``v4_order_context``v4_message_event``route_code`、系统处理分类和 `field_contract_version=20260718-v4`
- V4 入站校验和路由已拆分为独立 Validator / Router主业务 service 只负责编排、幂等和落库。
- V4 包级契约错误在 SourceMessage 可定位时只写 `adapter_contract_error` transition不创建订单、任务或用户可处理卡。
- `PAYMENT.attachment_ids[]` 必须能匹配 `source_message.attachments[].id`;不匹配时只写 `adapter_contract_error` transition不创建用户可处理业务任务。
- `UPDATE_BOOKING` 中出现 `rate_code``after.rate_code` 时按 `UPDATE_RATE_CODE_NOT_ALLOWED` 写入 `adapter_contract_error` transition。
- `manual_review` 只接受 `null` 或布尔 `true``true` 必须能由当前对象中可识别的未解决字段解释。
当前 CP4 已完成:
- 普通 V4 业务包按 `source_message_id + order_ref` 写入 `workflow_reservation_v4_order_task`
- 普通 V4 业务包固定创建 `SOURCE_MESSAGE_DISPLAY` 只读卡和 `BASIC_INFORMATION` 可确认 / 可复核卡。
- 合法 V4 event 按 `event_type` 创建 `ROOM_INFORMATION``TRACE_RESERVATION_NOTES``ROOMING_LIST``PAYMENT` 业务卡event 契约错误只落 AI transition。
- V4 S10/S99 写入 `workflow_reservation_v4_source_notification`,状态为 `ACK_REQUIRED`
当前 CP5 已完成:
- `GET /api/reservation/workbench-items` 查询 V4 工作台统一列表,混排 V4 业务订单任务和 S10/S99 来源通知。
- `GET /api/reservation/order-tasks` 查询 V4 业务订单任务列表,不包含 S10/S99 来源通知。
- `GET /api/reservation/order-tasks/{orderTaskId}` 查询 V4 订单任务详情按来源邮件展示卡、Basic Information 卡和业务卡拆分。
- `GET /api/reservation/source-notifications/{notificationId}` 查询 V4 S10/S99 来源通知详情。
- CP5 查询接口强制 Bearer 登录、`RESERVATION_TASK_READ` 和酒店访问权;不返回邮件正文、附件 URL、`ai_payload_json` 或来源通知原始 payload。
当前仍未完成:
- 普通 V4 业务包暂时仍保留旧 V3 任务状态、草稿和 OPERA 模拟骨架兼容便于前端过渡V4 写接口和前端页面完成后再逐步废弃旧链路。
- V4 卡片确认、复核解阻和 S10/S99 来源通知 ack 写接口。
- 尚未接入真实 PMS / OPERA / OHIP。
- 尚未改造前端 V4 页面模型。
## 26. 后端 CP2 设计文档状态
2026-07-18 已新增 `M002-v4-order-task-card-domain-model-cp2.md`,明确以下后续开发方向:
- 普通业务包按 `source_message_id + order_ref` 形成 V4 订单任务。
- 普通业务包固定展示来源邮件卡,但该卡只读、不阻塞、不替代邮件会话接口。
- 每个 `order_ref` 创建一张 Basic Information 卡。
- 每个 `message_events[]` event 创建一张业务卡,卡片按固定业务顺序展示。
- S10/S99 后续按来源通知模型实现,不再挂隐藏技术订单;只在任务列表 / 工作台展示,并进入纯通知详情页确认已读 / 已处理。
- `FIT + BOOKING_CODE` 不建立 ACTIVE 唯一约束;业务绑定查到多条时进入人工复核。
- V4 前端工作台统一列表为 `/api/reservation/workbench-items`,业务订单任务接口新开 `/api/reservation/order-tasks/**`S10/S99 来源通知详情为 `/api/reservation/source-notifications/{notificationId}`
- V4 新数据不再保存后端草稿;用户只提交最终确认或复核解阻。
- 卡片确认后锁定,错误修正后续通过审计和未来纠错流程表达,不覆盖原确认。
- 技术异常只进入 AI transition / 技术运行记录,不进入用户可处理卡。
- CP3 已新增 V4 订单任务表、V4 任务卡表和 V4 来源通知表,继续复用 SourceMessage、AI batch、AI transition、Reservation Order 和业务审计表。
CP3 只完成表结构、Entity、Mapper、Repository、幂等创建、`order_context_index` 稳定排序、非 event 卡 `source_event_index=0` 和基础乐观锁更新。CP4 已把 V4 回调写入新模型。CP5 已开放查询接口。后续开发应继续补卡片确认 / 复核、S10/S99 ack 和前端页面。