Files
th-hotel-simple/docs/project/requirements/M002-order-task-workflow-v2.md
2026-07-10 12:05:57 +08:00

568 lines
32 KiB
Markdown
Raw Permalink 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 Order Task Workflow 订单任务主流程 V2
## 文档信息
| 项目 | 内容 |
| --- | --- |
| 文档版本 | 0.3 |
| 日期 | 2026-07-10 |
| 状态 | 第二版需求与后端阶段实现记录 |
| 适用范围 | SourceMessage 之后的 AI 过渡层、订单挂靠、任务卡、人工确认、OPERA 模拟操作主流程 |
| 主要读者 | 产品、后端、前端、测试、后续协作 agent |
## 1. 文档定位
本文是 `M002-order-task-workflow-v1.md` 的第二版修正,目标是把本项目已经讨论确认的订单任务主流程,与 2026-07-06 导入的 AI 任务卡契约对齐。
本文定义业务边界、数据语义和后续实现约束。当前后端已经按拆分 checkpoint 实现了 AI 结果接收、S000/S999 特殊入口结果、订单任务基础流转、任务草稿保存、最终确认、审计列表、OPERA 模拟骨架、SuperAgent 查询上下文接口 1、2 的最小字段版,以及前端 P0 任务列表 / 订单详情查询接口;前端页面、真实 OPERA、普通任务切换订单、查询接口 3 和查询接口 4 仍未实现。
## 2. 本版核心修正
相对 V1本版有以下修正
- 增加 `AI 过渡层`:系统必须先保存 AI 原始输出,再生成订单、任务和任务卡。
- 不再使用 `EXCEPTION` 作为底层结果类型SuperAgent 结构化 JSON 新入口只使用 `normal_task``manual_review``informational_message` 仅保留历史兼容。
- 新增 SuperAgent 纯文本入口结果 `S000,source_message_id``S999,source_message_id`:两者都生成只读 `SOURCE_MESSAGE_ONLY` 特殊任务,任务列表可见,订单列表不可见。
- 系统主任务类型收敛为 `NEW_BOOKING``UPDATE_BOOKING``CANCEL_BOOKING``MANUAL_REVIEW`,另保留历史 `INFORMATIONAL_MESSAGE`,并新增 `SOURCE_MESSAGE_ONLY` 用于 S000/S999 特殊入口结果。
-`New Booking``Cancel Booking``Fallback/manual_review` 外,其他业务处理类卡片原则上都归到 `UPDATE_BOOKING` 下的不同任务卡。
- `Message Notification` / `INFORMATIONAL_MESSAGE` 只作为历史兼容路径;新数据中的纯信息类邮件由 `S000` 表达。
- 任务卡后端完整规则以 `任务卡展示编辑矩阵.xlsx` 为权威来源,不在代码里随意扩展或重命名字段路径。
- 前端展示 / 编辑白名单以最新导入的 `任务卡前端展示字段表 3.0.xlsx` 为准;该文件只约束前端展示和可编辑范围,不替代后端完整校验、确认写入和 OPERA 映射规则。
- 系统必须同时保存 AI 原始 `task_type`、系统主任务类型、任务卡类型和业务动作 subtype。
- `ai_payload_json``confirmed_payload_json` 必须分离。OPERA 模拟只能读取用户确认后的 `confirmed_payload_json`
- 订单业务号候选字段和 OPERA 模拟回填边界需要明确记录,但 OPERA 返回 JSON 字段名目前未知,不能写死。
## 3. 权威输入资料
本版需求参考以下资料:
| 资料 | 作用 |
| --- | --- |
| `docs/project/requirements/M001-source-message-inbox-prd.md` | 上游 SourceMessage Inbox 边界 |
| `docs/project/requirements/M002-order-task-workflow-v1.md` | 第一版整体业务流程 |
| `docs/import/20260706/开发AI先读_工作顺序.md` | AI 过渡表、任务卡、确认 payload 和 OPERA 写入工作顺序 |
| `docs/import/20260706/AI输出参数并集字典.xlsx` | AI 输出字段路径、字段含义、建议存储方式和索引建议 |
| `docs/import/20260706/任务卡展示编辑矩阵.xlsx` | 后端任务卡完整规则来源包括校验、确认写入、OPERA 映射和展示条件 |
| `docs/import/20260708/任务卡前端展示字段表 3.0.xlsx` | 前端任务卡展示 / 编辑白名单,不替代后端完整规则矩阵 |
| `docs/import/20260706/0630AI_副本 2/01_main_agent_prompt.md` | Main Agent 输出职责和聚合 JSON 结构 |
| `docs/import/20260706/0630AI_副本 2/02_agent_workflow.md` | AI 侧事件拆分、Skill 调用和结果聚合流程 |
| `docs/import/20260706/0630AI_副本 2/03_skill_catalog.md` | Skill 目录、结果类型、任务类型和统一输出字段 |
| `docs/import/20260706/0630AI_副本 2/skill/S01-S08*.md` | 各业务任务卡的抽取规则和边界 |
| `docs/import/20260706/0630AI_副本 2/references/qbd_liantai_email_table_rules.md` | QBD / LianTai 表格邮件拆分和证据规则 |
| `docs/import/20260706/0630AI_副本 2/skill/*/references/rate_code_rules.md` | Rate Code 判断规则 |
| `docs/import/20260706/0630AI_副本 2/skill/*/references/room_type_mapping_rules.md` | 房型映射规则 |
说明:`开发AI先读_工作顺序.md` 中提到的 `AI过渡表开发契约_README.md``AI过渡表开发契约_两张样例表.xlsx` 在当前导入目录下未找到同名文件。当前以后端完整规则矩阵、AI 输出参数字典和前端 3.0 白名单共同作为字段来源;三者职责不同,不能互相覆盖。
## 4. 总体流程
```text
AgentBus / 未来其他入口
→ SourceMessage Inbox 记录原始来源事实
→ SuperAgent / Main Agent 读取 SourceMessage 并拆分 current 事件
→ 对每个事件调用对应 Skill
→ 聚合输出 source_message_id + ai_task_results[] + extraction_warnings[]
→ 本系统接收 AI 结果并写入 AI 过渡层
→ 本系统根据 result_type + task_type + task_subtype 生成订单、任务和任务卡
→ 用户在任务详情页查看、修改字段、确认订单归属
→ 系统生成 confirmed_payload_json
→ 用户触发 OPERA 模拟操作
→ 系统保存每条模拟操作结果、失败原因和重试记录
```
特殊分支:
```text
SuperAgent 返回 S000,source_message_id 或 S999,source_message_id
→ 本系统按默认酒店 + external_message_id 反查 SourceMessage Inbox
→ 创建隐藏技术订单 + SOURCE_MESSAGE_ONLY 只读任务
→ 任务列表可见,订单列表不可见
→ 不允许编辑、确认、转换、OPERA 模拟或重试
```
中文说明:
- `SourceMessage Inbox` 是来源事实层,不表达订单、任务或业务结论。
- AI 只输出 JSON不直接写数据库、不直接创建真实任务卡、不直接写 OPERA。
- 本系统负责保存 AI 原始 JSON、创建任务卡、接收用户修改、生成确认后的 payload、执行 OPERA 模拟并记录结果。
- SuperAgent 不直连本系统数据库,只能通过本系统后端接口查询已有订单和任务上下文。
- S000/S999 不是业务任务,也不是人工复核任务,只是来源邮件入口处理结论。
## 5. AI 输出接收边界
导入文档已经定义了 SuperAgent / Main Agent 应输出的核心业务结构。当前正式 HTTP 接口同时支持结构化 JSON 和 S000/S999 纯文本入口结果。
AI 聚合输出的顶层结构应包含:
| 字段 | 中文说明 |
| --- | --- |
| `source_message_id` | SuperAgent / Main Agent 原样带回的外部来源消息 ID对应 AgentBus `source.external_message_id`,不是本系统内部 SourceMessage Inbox 主键 |
| `ai_task_results[]` | AI 拆分出的一个或多个任务结果,顺序必须保留 |
| `extraction_warnings[]` | 抽取警告,不直接等同于业务任务 |
结构化 JSON 的 `ai_task_results[]` 中关键字段包括:
| 字段 | 中文说明 |
| --- | --- |
| `source_event_index` | AI 拆分出的 current 事件序号,同一次来源消息内用于排序 |
| `catalog_code` | Skill 目录代码,例如 S01、S02 |
| `skill_id` | 具体 Skill 标识 |
| `result_type` | AI 结果类型,新入口只使用 `normal_task``manual_review``informational_message` 仅历史兼容 |
| `task_type` | AI 原始任务类型,例如 `New Booking``Voucher Received` |
| `task_subtype` / 业务动作 | 更细的业务动作,用于任务卡字段路由 |
| `current_or_history` | 当前事件还是历史证据 |
| `case_keys` | 订单关联候选键,例如 `group_code``confirmation_number` |
| `visible_reason` | 给用户看的生成原因 |
| `relevant_message_excerpt` | 相关邮件片段 |
| `attachments` / `file_references` | 附件和文件引用 |
| `context_used` | AI 使用的上下文摘要 |
| `extracted_fields` | 业务字段主体 |
| `manual_review` | 人工复核结构化原因和证据 |
| `informational_message` | 信息提醒内容,仅历史兼容 |
| `additional_operations` | AI 建议的附加动作 |
| `idempotency_key` | 幂等键,最终来源和生成规则待确认 |
HTTP 契约已在 `docs/project/requirements/M002-superagent-task-result-api-contract.md``docs/project/integrations/superagent-api-contract.md` 中补充。正式契约要求任务结果通知携带 `hotel_id + source_message_id`,其中 `source_message_id` 是外部来源消息 ID后端会反查内部 SourceMessage Inbox ID 后再写入 `workflow_*` 表。
纯文本入口结果格式:
```text
S000,source_message_id
S999,source_message_id
```
中文说明:
- `S000` 表示纯信息类邮件,不形成业务素材包。
- `S999` 表示入口阶段无法形成业务素材包。
- `source_message_id` 是外部来源消息 ID对应 AgentBus `source.external_message_id`
- 第一版使用系统默认酒店反查 SourceMessage Inbox。
- 命中 SourceMessage 后创建 `SOURCE_MESSAGE_ONLY` 只读任务,并挂到 `order_visibility=HIDDEN_SYSTEM` 的技术订单下。
## 6. AI 过渡层数据要求
系统接收 AI 输出后,应先写入 AI 过渡层,再创建任务卡。过渡层用于追溯、幂等、筛选、人工确认和 OPERA 参数组装。
推荐保存完整 JSON
| JSON 字段 | 中文说明 |
| --- | --- |
| `ai_payload_json` | AI 原始结果,禁止被用户编辑覆盖 |
| `case_keys_json` | AI 给出的订单关联候选键 |
| `extracted_fields_json` | AI 抽取的业务字段 |
| `manual_review_json` | 人工复核信息 |
| `informational_message_json` | 信息提醒内容,仅历史兼容 |
| `attachments_json` | 附件和文件引用 |
| `context_used_json` | AI 使用的上下文 |
| `confirmed_payload_json` | 用户修改并确认后的最终参数 |
推荐冗余物理列:
| 物理列 | 中文说明 |
| --- | --- |
| `source_message_id` | 内部 SourceMessage Inbox ID来自外部 `source_message_id` 反查后的 `platform_source_message_inbox.id` |
| `source_event_index` | AI 事件序号 |
| `catalog_code` | Skill 目录代码 |
| `skill_id` | Skill 标识 |
| `result_type` | AI 结果类型S000/S999 内部保存为 `source_message_only` |
| `ai_task_type` | AI 原始任务类型 |
| `system_task_type` | 系统主任务类型S000/S999 为 `SOURCE_MESSAGE_ONLY` |
| `task_card_type` | 任务卡类型 |
| `task_subtype` | 业务动作 subtype |
| `current_or_history` | 当前或历史标识 |
| `group_code` | 冗余的 Group Code 候选 |
| `confirmation_number` | 冗余的 Confirmation Number 候选 |
| `idempotency_key` | 幂等键 |
| `manual_reason_code` | 人工复核原因码 |
| `parent_source_event_index` | 父任务事件序号 |
| `linked_task_group_id` | 联动任务组 ID |
| `blocked_until_parent_completed` | 是否等待父任务完成 |
| `execution_order` | 同订单下执行顺序 |
| `created_at` / `updated_at` | 创建和更新时间 |
不要把所有嵌套字段都建成物理列。只有高频查询、筛选、幂等、排序、队列控制和状态机需要的字段才冗余。
## 7. 任务分类模型
### 7.1 AI 结果类型
AI 新入口结构化 JSON 结果类型只接受:
| `result_type` | 中文说明 | 是否可直接 OPERA 模拟 |
| --- | --- | --- |
| `normal_task` | 可生成业务任务卡的正常任务 | 需用户确认后才允许 |
| `manual_review` | 需要人工复核的结构化任务 | 不允许直接写 OPERA |
| `informational_message` | 只读信息提醒,仅历史兼容 | 不允许写 OPERA |
不使用 `exception_task``no_action`。原来讨论中的异常任务,在本版统一落为 `manual_review`;没有业务动作的信息类邮件,新入口不再生成 `informational_message` JSON而是返回 `S000,source_message_id`
S000/S999 不属于结构化 `result_type`,它们是纯文本入口结果,系统内部保存为 `source_message_only` 过渡记录和 `SOURCE_MESSAGE_ONLY` 只读任务。
### 7.2 系统主任务类型
系统内部主任务类型建议为:
| 系统主任务类型 | 中文说明 |
| --- | --- |
| `NEW_BOOKING` | 新建订单任务 |
| `UPDATE_BOOKING` | 更新订单任务,下面承载多个不同任务卡 |
| `CANCEL_BOOKING` | 取消订单任务 |
| `MANUAL_REVIEW` | 人工复核或 Fallback 任务 |
| `INFORMATIONAL_MESSAGE` | 信息提醒任务,只归档展示,不参与执行队列,仅历史兼容 |
| `SOURCE_MESSAGE_ONLY` | S000/S999 来源消息入口结果任务,只读展示,不参与执行队列 |
### 7.3 AI 任务类型到系统任务和卡片的映射
| AI `task_type` | 系统主任务类型 | 任务卡类型 | 说明 |
| --- | --- | --- | --- |
| `New Booking` | `NEW_BOOKING` | `NEW_BOOKING` | 新建 FIT、Group Block、Allotment / Control Block |
| `Update Booking` | `UPDATE_BOOKING` | `UPDATE_BOOKING` | 通用订单修改卡 |
| `Voucher Received` | `UPDATE_BOOKING` | `VOUCHER_RECEIVED` | 凭证类更新卡 |
| `Rooming List` | `UPDATE_BOOKING` | `ROOMING_LIST` | 名单/分房表处理卡 |
| `Amend Group Code` | `UPDATE_BOOKING` | `AMEND_GROUP_CODE` | 修改 Group Code 卡 |
| `Trace / Reservation Notes` | `UPDATE_BOOKING` | `TRACE_RESERVATION_NOTES` | Trace 或备注卡,可作为联动任务 |
| `TA Recorder` | `UPDATE_BOOKING` | `TA_RECORDER` | TA Recorder 维护卡,通常由 Rooming List 派生 |
| `Cancel Booking` | `CANCEL_BOOKING` | `CANCEL_BOOKING` | 取消 FIT、Group Block、Allotment / Control Block |
| `Message Notification` | `INFORMATIONAL_MESSAGE` | `MESSAGE_NOTIFICATION` | 历史兼容路径;新纯信息类邮件改用 S000 |
| `Fallback` | `MANUAL_REVIEW` | `FALLBACK_REVIEW` | 人工复核任务 |
| `S000` 文本结果 | `SOURCE_MESSAGE_ONLY` | `SOURCE_MESSAGE_ONLY` | 纯信息类邮件,任务列表可见,订单列表不可见 |
| `S999` 文本结果 | `SOURCE_MESSAGE_ONLY` | `SOURCE_MESSAGE_ONLY` | 无法形成业务素材包,任务列表可见,订单列表不可见 |
系统不得丢弃 AI 原始 `task_type`。任务落库时应同时保存 AI 原始任务类型、系统主任务类型、任务卡类型和业务动作 subtype。
## 8. S000/S999 和历史 Message Notification 处理规则
### 8.1 S000/S999 处理规则
`S000` / `S999` 是 SuperAgent 入口阶段返回的纯文本结果,不是结构化任务 JSON。
本系统处理规则:
- `S000` 表示纯信息类邮件。
- `S999` 表示无法形成业务素材包。
- 两者都按外部 `source_message_id` 反查 SourceMessage Inbox。
- 第一版使用系统默认酒店,不要求请求体携带 `hotel_id`
- 创建 `SOURCE_MESSAGE_ONLY` 只读任务,`task_subtype` 分别为 `S000``S999`
- 创建 `order_visibility=HIDDEN_SYSTEM` 的技术订单,仅用于满足任务归属,不进入订单列表和订单详情。
- 任务状态为 `COMPLETED``queue_participation=false`
- 任务列表可见;订单列表不可见。
- 任务详情可查看来源邮件、会话、附件和 SuperAgent 原始返回。
- 不允许保存草稿、最终确认、人工转换、普通切换订单、执行 OPERA 模拟或重试 OPERA。
- 不阻塞任何订单任务,也不被任何订单任务阻塞。
### 8.2 历史 Message Notification 处理规则
`Message Notification` 用于感谢、知会、已收到、转发说明、信息同步等没有明确业务执行动作的消息。
该路径仅为历史兼容,新数据应由 SuperAgent 返回 `S000,source_message_id`。历史数据处理规则:
- 创建临时订单作为归档容器。
- 创建只读信息提醒任务卡。
- 不参与订单任务执行队列。
- 不阻塞同订单其他可执行任务。
- 不被同订单其他可执行任务阻塞。
- 不允许编辑业务字段。
- 不允许确认后执行 OPERA 模拟。
- 可在详情页展示 `visible_reason``relevant_message_excerpt``attachments``informational_message`
## 9. 任务卡字段约束
任务卡字段来源按职责拆分:
- 后端校验、确认写入、OPERA 映射和展示条件以 `docs/import/20260706/任务卡展示编辑矩阵.xlsx` 为权威来源。
- 前端展示 / 编辑白名单以 `docs/import/20260708/任务卡前端展示字段表 3.0.xlsx` 为准。
- 系统不得直接把整个 `ai_task_results[]` 渲染成表单,也不得绕过矩阵自行扩展字段含义。
- 如果后端完整规则与前端白名单出现冲突,例如旧矩阵要求必填但 3.0 白名单未开放展示或编辑,应先记录为前后端契约待确认问题,不由前端或后端单方面放宽规则。
字段矩阵通过以下列控制任务详情页行为:
| 列 | 中文说明 |
| --- | --- |
| `任务卡名称` | 前端任务卡名称 |
| `result_type` | 适用的 AI 结果类型 |
| `task_type` | 适用的 AI 原始任务类型 |
| `task_subtype/业务动作` | 适用的业务动作 |
| `字段路径` | 从 AI JSON 或确认 JSON 中取值的路径 |
| `展示名` | 前端展示名称 |
| `是否展示` | 是否在任务卡展示 |
| `是否可编辑` | 用户是否可编辑 |
| `是否为输入方式编辑` | 是否普通输入 |
| `是否为下拉框方式编辑` | 是否下拉选择 |
| `是否日期选择` | 是否日期控件 |
| `是否数字输入` | 是否数字输入 |
| `是否文件展示` | 是否文件或附件展示 |
| `是否表格编辑` | 是否表格型编辑 |
| `下拉选项/枚举值` | 可选值,系统不得自行扩展 |
| `是否必填` | 用户确认前是否必填 |
| `展示条件` | 字段显示条件 |
| `校验规则` | 用户确认前校验规则 |
| `确认后写入位置` | 写入 `confirmed_payload_json` 的位置 |
| `是否参与Opera写入` | 是否允许进入 OPERA 参数 |
| `Opera API参数映射` | OPERA 参数映射意图 |
### 9.1 关键卡片字段摘要
本节只摘录核心字段,完整字段以 Excel 矩阵为准。
| 任务卡 | 关键字段 |
| --- | --- |
| New Booking | `case_keys.group_code``case_keys.confirmation_number`、入住/离店日期、房量、房型原文、Opera 房型代码、Rate Code、结算价、Fix Charge、子团房量、表格行证据 |
| Update Booking | `case_keys.group_code``case_keys.confirmation_number`、修改类型、修改前/后、Rate / 结算价结果、Fix Charge、表格行证据 |
| Cancel Booking | `case_keys.group_code``case_keys.confirmation_number`、取消对象类型、取消范围、取消生效日期、取消备注 |
| Voucher Received | 原始凭证、凭证类型、`case_keys.group_code`、确认后动作、凭证展示字段、部门流转、关联 Group Code |
| Rooming List | 名单文件、名单类型、目标 Key、文件类型判断、附件 / Sheet 绑定、后续动作意图、派生任务候选 |
| Amend Group Code | 旧 Group Code、新 Group Code |
| Trace / Reservation Notes | `case_keys.group_code``case_keys.confirmation_number`、Trace 类型、通知部门、Trace Text、入住人数更新、改价公式、父任务事件序号 |
| TA Recorder | Group Code、名单 / 分房附件、TA Recorder 状态、Rooming List 父任务 |
| Message Notification | 生成原因、邮件片段、附件、信息提醒内容 |
| Fallback / manual_review | 复核原因码、复核说明、复核记录类型、阻断点、缺失字段、冲突点、建议核对证据、建议人工动作、候选 Group Code、候选 Confirmation No. |
## 10. AI 原始值和人工确认值
AI 原始输出和用户确认值必须分离。
| 概念 | 中文说明 |
| --- | --- |
| `ai_payload_json` | AI 原始输出,作为证据和审计,不被用户编辑覆盖 |
| `confirmed_payload_json` | 用户修改并确认后的最终业务参数 |
系统规则:
- 任务详情首次展示可从 `ai_payload_json` 按矩阵字段路径取值。
- 用户编辑后必须写入 `confirmed_payload_json`
- 用户确认前必须按矩阵和后端硬校验检查必填、类型、枚举和执行条件。
- OPERA 模拟只能从 `confirmed_payload_json` 取值。
- 不允许直接从 `ai_payload_json` 组装 OPERA 参数。
- 不允许因为用户修改而覆盖 AI 原始输出。
## 11. 订单业务号和临时订单
系统不应只用一个含义模糊的“订单号”。建议至少区分:
| 字段 | 中文说明 |
| --- | --- |
| `order_id` | 系统内部订单 ID永远存在 |
| `order_key_type` | 业务号类型,例如 `GROUP_CODE``CONFIRMATION_NUMBER``TEMPORARY` |
| `order_business_key` | 真实业务号,例如 Group Code 或 Confirmation Number |
| `temporary_order_code` | 临时订单展示编号 |
### 11.1 可作为订单业务号候选的字段
订单业务号候选字段包括:
| 字段路径 | 适用场景 | 中文说明 |
| --- | --- | --- |
| `case_keys.group_code` | Group / Block / Allotment 类任务 | 主要 Group Code 候选 |
| `case_keys.confirmation_number` | FIT Reservation 类任务 | 主要 Confirmation Number 候选 |
| `extracted_fields.old_group_code` | Amend Group Code | 定位原订单 |
| `extracted_fields.new_group_code` | Amend Group Code | 修改成功后的新业务号候选 |
| `extracted_fields.group_code` | TA Recorder 等卡片 | 任务卡内 Group Code 候选 |
| `extracted_fields.target_key` | Rooming List | 目标 Key需要判断实际是 Group Code 还是 Confirmation Number |
| `related_group_codes[]` | Voucher 等场景 | 关联展示或候选,不应自动作为唯一主订单号 |
系统匹配订单时应优先使用用户确认后的 `confirmed_payload_json`;如果尚未确认,只能把 AI 字段作为候选和展示依据。
### 11.2 New Booking 的订单号处理
`NEW_BOOKING` 不一定都需要等待 OPERA 模拟创建后才有真实业务号。
规则:
- 如果用户确认后的 payload 已有可用业务号,优先使用该业务号。
- FIT Reservation 优先看 `confirmation_number`
- Group / Block / Allotment 优先看 `group_code`
- 如果确认后的 payload 没有可用业务号,先创建临时订单并使用 `temporary_order_code` 展示和追踪。
- OPERA 模拟创建成功后,如果结果中返回真实业务号,再回填订单业务号。
- 第一版尚未实现确认 payload 时Fallback 转 `NEW_BOOKING` 可先读取 AI 原始 `case_keys.group_code` / `case_keys.confirmation_number` 作为 `AI_CANDIDATE`,用于把原临时订单激活为 ACTIVE后续用户确认字段时再把来源升级为 `USER_CONFIRMED`
### 11.3 什么时候从 OPERA 模拟结果回填订单号
只有在 `NEW_BOOKING` 且确认后的 payload 没有可用业务号时,才需要从 OPERA 模拟结果回填订单号。
| 任务场景 | 回填业务含义 |
| --- | --- |
| New FIT Reservation | 从 OPERA 模拟结果中的 Confirmation No. / Reservation Confirmation Number 含义字段回填 |
| New Group Block | 从 OPERA 模拟结果中的 Group Code / Block Code 含义字段回填 |
| New Allotment / Control Block | 从 OPERA 模拟结果中的 Group Code / Block Code / Allotment Code 含义字段回填 |
当前导入文档没有定义 OPERA 模拟结果的 JSON 字段名,因此不能在需求中写死 `result.confirmationNumber``result.groupCode` 等具体路径。该字段名需要在 OPERA 模拟模块设计时另行确认。
### 11.4 非 New Booking 的订单号规则
`UPDATE_BOOKING``CANCEL_BOOKING``Voucher Received``Rooming List``Trace / Reservation Notes``TA Recorder` 等任务,原则上不应依赖 OPERA 模拟结果生成订单号。
这些任务应先通过 `case_keys` 或对应卡片字段挂靠已有订单;如果无法自动归属,则创建或使用临时订单,并等待人工确认订单关系。
## 12. 订单挂靠和临时订单
任务必须挂靠到订单下,便于详情查看、队列控制和审计。
| 场景 | 挂靠规则 |
| --- | --- |
| New Booking 有业务号 | 按确认后的业务号创建或匹配订单 |
| New Booking 无业务号 | 创建临时订单 |
| Update Booking 可匹配已有订单 | 挂靠已有订单 |
| Update Booking 无法匹配订单 | 挂靠临时订单,等待人工确认 |
| Cancel Booking 可匹配已有订单 | 挂靠已有订单 |
| Cancel Booking 无法匹配订单 | 挂靠临时订单,等待人工确认 |
| Fallback / manual_review | 先挂靠临时订单,人工处理时可转换类型和订单归属 |
| Message Notification | 挂靠临时订单,只读归档 |
任务从临时订单迁移到已有订单时,必须记录审计。若原临时订单已无有效任务,应逻辑删除,并记录删除原因。
## 13. 任务顺序和可处理状态
同一个订单下,任务必须按顺序处理。
排序依据:
```text
order_id + execution_order
```
同一次 AI 返回多个任务时:
- 必须保留 `ai_task_results[]` 列表顺序。
- 可使用 `source_event_index``execution_order` 或批次内 item index 保存顺序。
- 不得只依赖创建时间,因为同批次任务创建时间可能完全一致。
处理规则:
- 前置任务未完成时,后续任务只能查看。
- `FAILED` 视为当前前置任务已经结束,不阻塞后续任务;用户不能跳过失败的 OPERA 操作,但失败任务本身不再卡住后续任务查看和处理顺序。
- 后续任务不能编辑字段。
- 后续任务不能确认订单关系。
- 后续任务不能执行 OPERA 模拟。
- 后续任务不能重试 OPERA 模拟。
- `Message Notification` 不参与执行队列,不阻塞其他任务,也不被其他任务阻塞。
- 联动任务可通过 `parent_source_event_index``linked_task_group_id``blocked_until_parent_completed` 表达依赖。
## 14. 人工复核和 Fallback
`manual_review` 是结构化人工复核,不是空结果,也不是系统失败。
人工复核卡至少应展示:
- `manual_review.reason_code`
- `manual_review.visible_reason`
- `manual_review.review_record_type`
- `manual_review.blocking_points[]`
- `manual_review.missing_fields[]`
- `manual_review.conflicting_points[]`
- `manual_review.evidence_to_check[]`
- `manual_review.suggested_human_actions[]`
Fallback 处理规则:
- 创建 `MANUAL_REVIEW` 任务。
- 默认挂靠临时订单。
- 用户处理时可以选择转为 `NEW_BOOKING``UPDATE_BOOKING``CANCEL_BOOKING`
- 转换时必须记录审计;原因字段第一版允许为空。
- 转为 `NEW_BOOKING` 时,临时订单可以继续保留;如果已有确认 payload 则优先使用确认业务号,第一版尚未实现确认 payload 时可先使用 AI 原始 `case_keys` 中的业务号候选。
- 转为 `UPDATE_BOOKING``CANCEL_BOOKING` 时,用户必须选择目标订单;任务迁移后原临时订单无有效任务时可逻辑删除。
- 类型转换、订单迁移和临时订单逻辑删除都必须记录审计。
## 15. OPERA 模拟操作
当前阶段没有真实 OHIP / OPERA 接口,只做 OPERA 模拟操作。
允许进入 OPERA 模拟的前置条件:
- `result_type = normal_task`
- 当前任务是订单执行队列中可处理的任务。
- 用户已确认订单归属。
- 用户已确认字段,且系统已生成 `confirmed_payload_json`
- 字段矩阵中 `是否参与Opera写入``是` 或满足 `条件参与`
- 后端硬校验通过。
不允许进入 OPERA 模拟的场景:
- `manual_review`
- `informational_message`
- 未确认的 AI 原始值。
- 证据字段、只读字段、历史字段、uncertain 字段。
- S04 的 `voucher_display_fields` 等展示字段。
- 字段矩阵明确 `是否参与Opera写入=否` 的字段。
一个任务可能产生多条 OPERA 模拟操作。任务详情页应展示每条模拟操作的结果、状态、失败原因、重试次数和最近执行时间。重试必须保留历史记录,不能覆盖原始失败记录。
第一版后端实现中,任务最终确认后固定生成两条 OPERA 模拟操作:
| 顺序 | 操作代码 | 中文说明 |
| --- | --- | --- |
| 1 | `SIMULATE_PRECHECK` | OPERA 模拟预检查 |
| 2 | `SIMULATE_WRITE` | OPERA 模拟写入 |
当前模拟操作只保存请求/响应摘要和 attempt 记录,不接真实 OPERA也不从模拟结果回填订单业务号。失败时只把对应操作标记为 `FAILED`,任务保持未完成,避免用户绕过失败操作。
## 16. 审计要求
以下行为必须记录审计:
- AI 结果接收批次。
- `ai_task_results[]` 中每个 item 的创建顺序。
- AI 原始 JSON 保存。
- 订单自动挂靠或临时订单创建。
- 用户修改任务字段。
- 用户确认订单关系。
- `confirmed_payload_json` 生成。
- 任务类型转换。
- 任务切换订单。
- 临时订单逻辑删除。
- OPERA 模拟操作执行。
- OPERA 模拟操作重试。
- 从 OPERA 模拟结果回填订单业务号。
审计至少包含:
| 字段 | 中文说明 |
| --- | --- |
| `actor` | 操作人或系统调用方 |
| `action` | 操作类型 |
| `reason` | 用户填写或系统记录的原因 |
| `before_snapshot` | 变更前摘要 |
| `after_snapshot` | 变更后摘要 |
| `occurred_at` | 发生时间 |
审计中不得记录 Secret、Token、完整邮件正文、真实附件 URL 或不必要的个人敏感信息。
## 17. 暂不包含范围
本版暂不定义:
- SuperAgent 查询上下文接口 3、4接口 1、2 的第一版最小字段已单独定义并落地在 `M002-ai-query-minimal-fields.md`
- OPERA 模拟结果 JSON 字段名。
- 真实 OHIP / OPERA 接口地址、鉴权和返回结构。
- 前端具体页面布局和交互细节。
- 全量 158 条任务卡字段配置复制版。
- Rate Code 和房型规则的代码实现。
- 普通任务切换订单接口和前端交互。
- 用户身份、权限和真实 actor 注入。
## 18. 待确认问题
- SuperAgent 创建任务接口的 URL、Method、Header、鉴权和错误响应格式。
- SuperAgent 查询上下文接口 1、2 已实现最小字段版,并已启用与任务结果接收接口一致的 HMAC接口 3 文件解析和接口 4 订单及任务查询仍需后续确认与实现,后续梳理未完成事项时必须持续提醒。
- SuperAgent 任务结果通知中的 `source_message_id` 已确认是外部来源消息 ID对应 AgentBus `source.external_message_id`;查询接口中的 `source_message_id``source_event_index` 第一版接收但忽略。
- `source_event_index`、批次 item index、`execution_order` 的最终编号规则是否都从 1 开始。
- SuperAgent 查询上下文接口 3、4 的 URL、入参、返回字段和鉴权方式。
- `Message Notification` 是否需要在前端订单列表上单独标识为只读提醒。
- OPERA 模拟结果中 Confirmation No.、Group Code、Block Code、Allotment Code 的具体字段路径。
- 临时订单在无任务后是否立即逻辑删除,还是保留一段时间便于追溯。
- 普通任务切换订单接口何时纳入实现。
- 用户身份和权限体系何时接入,审计 `actor` 如何从登录态获取。
## 19. 后续建议 checkpoint
建议后续按以下顺序拆分:
1. 定义 SuperAgent 调本系统的任务结果接收接口契约。
2. 定义 AI 过渡层、订单、任务、任务卡、审计、OPERA 模拟结果的最小数据模型。
3. 定义系统主任务类型、任务卡类型、`result_type`、任务状态和订单状态枚举。
4. 实现 AI 结果接收、幂等、顺序保存和任务卡创建。
5. 实现订单自动挂靠、临时订单创建和人工订单切换。
6. 实现任务详情字段展示、编辑、确认和 `confirmed_payload_json`。当前后端已实现保存草稿和最终确认接口,前端页面待定。
7. 实现任务队列阻塞规则和 `Message Notification` 只读归档规则。当前后端已实现阻塞规则和只读提醒归档的基础能力,前端页面待定。
8. 实现 OPERA 模拟操作结果底表、重试和订单业务号回填。当前后端已实现固定两条模拟操作、attempt、执行、重试和审计列表订单业务号回填待真实 OPERA 返回结构确认后再做。
9. 根据前端页面范围实现列表、详情和只读/可处理状态展示。当前后端已实现 `GET /api/reservation/tasks``GET /api/reservation/orders/{orderId}` 第一版前端页面和订单列表、Message Notification 独立列表 / 详情、任务卡字段白名单元数据接口仍待后续确认。