Files
th-hotel-simple/docs/project/requirements/booking-email-architecture-v0.4.md
T
鲨鱼辣椒 694c4317a3 checkpoint: complete recoverable V2 pre-separation baseline
Complete the selective V2 checkpoint with its minimal AgentBus, object-storage, replay persistence, and validated-workbench shared dependency closure.
2026-08-20 17:09:00 +08:00

146 lines
13 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.
# Booking 邮件处理架构 v0.4
> **迁移状态(2026-08-13)**:本版本仅用于旧 V4 读取和迁移回归。它曾配套的 CandidateDecision v1 正式契约
> 从未上线且已删除。新运行只以 [v0.5](booking-email-architecture-v0.5.md)、
> [contracts-v2](booking-email-contracts-v2.md) 和 ADR-012 为准;不得依据本文件产生新业务结果。
| 项目 | 内容 |
| --- | --- |
| 文档状态 | 历史读取兼容;新写入已由 v0.5 取代 |
| 架构版本 | `booking-architecture-v0.4` |
| 契约版本 | `booking-contracts-v1` |
| 业务基线 | `BR00-BASELINE-1` |
| 范围终点 | 用户确认;不调用 PMS、Opera、付款或部门流转 |
## 1. 目的与替代关系
本架构把邮件获取、附件识别、固定渠道确定性解析、历史上下文、Booking Agent、校验和人工确认收敛为一条可追溯主线。它替代以附件 Parser 或旧 V4 入站模型为中心的实施方式。
早期 `architecture-v0.3`、M002 叙述和 M012 V0.1 实现记录只可用于迁移和回归,不能作为新功能实施依据。
新增实现必须使用 v0.5 与 contracts-v2;本文件不再指向或定义旧 CandidateDecision 契约。
## 2. 七层职责与边界
| 层 | 负责什么 | 输入 | 输出 | 不负责什么 |
| --- | --- | --- | --- | --- |
| 1. 信息系统接入与编排 | 接收 AgentBus 邮件或手工 EML,建立幂等、处理批次与状态查询 | AgentBus payload / `.eml` | `SourceMessageEnvelope` | 不理解业务、不直接建最终任务 |
| 2. 材料预处理 | 分离 current/quoted history,列举附件、图片、工作簿结构和候选材料,保留证据引用 | `SourceMessageEnvelope` | `MaterialPackage` | 不把历史内容重复当作本次动作 |
| 3. 确定性 Parser + 字段恢复与本地组装 | 对适用固定渠道生成不可变来源观察与 AFTER/CURRENT facts;只将 `UNRESOLVED+RECOVERABLE` 字段送字段解析兜底 Agent,再由本地校验、依赖重算与投影形成统一有效事实视图 | `MaterialPackage` | `ParsedFactSet`(含 `ParserObservationSet`)+ `EffectiveFactView` | 不做 Rate/Room 目录映射,不让 Agent 重写整行,不做最终业务决定 |
| 4. Context Assembler + RateRoomResolver | 按 Group Code、订单线索或会话定向读取当前态;并将 Layer 3 `source_room_type/source_price` 与版本化 Rate/Room 目录确定性解析 | `EffectiveFactView` + 来源/历史线索 + Rate/Room 目录 | `ContextPackage`(含 `rate_room_resolutions`) | 不扫描全库、不让历史邮件重新触发动作、不回写 Layer 3 来源事实 |
| 5. 业务识别 / Booking Agent | 合并 Layer 3 有效事实和 Context,形成候选业务决定;Parser 失败/不适用/歧义时使用受控最小 ParsedFactSet 分支 | 固定渠道:`EffectiveFactView + ContextPackage`;其他分支:最小 `ParsedFactSet + ContextPackage` | `CandidateDecision` | 不下载附件、不直接读写数据库、不建最终任务、不调用 PMS |
| 6. Validator 与人工确认准备 | 校验 schema、Catalog、证据、目标、生命周期、前置关系和确认必填项 | `CandidateDecision` | `ValidationResult`、`ConfirmationProjection` | 不绕过校验建卡、不执行外部业务动作 |
| 7. 用户确认 | 展示安全的关键参数、证据、阻断、可编辑字段和链接动作;冻结已确认参数与审计 | `ConfirmationProjection` | `CONFIRMED` 记录 | 不调用 PMS/Opera,不改变付款或部门状态 |
### 2.1 信息系统与 Agent 的职责分界
- **信息系统**拥有 SourceMessage、幂等、附件/证据存储、确定性 Parser、本地 Recovery 校验/组装、RateRoomResolver、Context 查询、Validator、数据库事务、确认 API 和审计。
- **AgentBus**既是邮件消息入口适配器,也是 Booking Agent 的承载平台;它不成为业务事实源。
- **Booking Agent**对固定渠道只消费最小化的 `EffectiveFactView + ContextPackage`;Parser 不适用等分支可消费最小 `ParsedFactSet + ContextPackage`,其中唯一的正文材料是 policy 脱敏、限长的 `agent_input_material` current excerpt。它不能自行扩大材料范围、下载附件、调用 PMS 或写任务表。
- Rate/Room 目录从 Layer 4 开始使用独立 `catalog_version`;Layer 3 只记录 Parser normalization catalog/version,不消费 207 行目录,也不生成 canonical Room Type 或最终 Rate Code。Booking Agent 只消费 Layer 4 的受控解析结果,不能自行重做目录映射。
- `Name of Group`、`Group Name`、`Tour Code`、`Group Code` 是固定渠道对同一团号的不同列名;第 3 层统一写入 `group_code`,第 4 层也只以该统一值定向查询,不能把列名差异制造成多目标。
### 2.2 Layer 3 固定渠道内部链路
Layer 3 固定为:`Deterministic Parser → ParserObservationSet + AFTER/CURRENT facts → RecoveryRequestBuilder → 字段解析兜底 Agent → RecoveryPatchSet → 本地 RecoveryPatchValidator / dependency resolver / projector → EffectiveFactView`。详细字段身份、状态、patch 校验和 overlay 规则只在唯一共用协调契约 `../../../../.planning/booking_completion_roadmap/fixed_channel_parser_recovery_contract_v2_discussion_draft.md` 维护;本文只冻结层间边界,不复制第二套格式。
- `parser_observations` 是不可变来源观察,保存 BEFORE/AFTER/CURRENT、raw/normalized value、稳定 row/segment/room/field/evidence 身份及未解决原因;原 Parser facts 不被 Agent 改写。
- `facts[]` 只承载 Parser 首次确定的 AFTER/CURRENT 当前事实;BEFORE 只用于展示和审计。
- Recovery 只允许处理持久 `UNRESOLVED+RECOVERABLE` 的稳定 `field_id`,Agent 只能返回候选 PatchSet;冲突、结构问题、业务合并和校验失败保持人工复核。
- accepted patch 先经过本地校验和同版依赖重算,再使用与 Parser 相同的 current-fact projector 形成 `EffectiveFactView`;没有恢复任务时也建立同格式 baseline view。
- Layer 3 房型名固定为 `source_room_type`。`room_type_code` 和最终 Rate Code 只属于 Layer 4 `RateRoomResolver`;QBD F 列完全忽略,且 `source_rate_code=NOT_APPLICABLE`。
## 3. 统一状态机
处理运行(processing run)使用以下状态;状态是运行主线,不等同于单张业务卡的用户可见状态:
```text
RECEIVED
→ MATERIAL_READY
→ PARSER_COMPLETE | PARSER_NOT_APPLICABLE | PARSER_FAILED
→ CONTEXT_READY
→ AGENT_COMPLETE(仅在需要 Agent 时)
→ VALIDATED
→ AWAITING_CONFIRMATION
→ CONFIRMED
```
- `PARSER_FAILED`、`PARSER_NOT_APPLICABLE` 不代表整封邮件失败;它们是允许进入 Context 和按需 Agent 的受控分支。
- 对适用固定渠道,`PARSER_COMPLETE` 的 Layer 3 artifact 必须进一步形成 baseline 或 recovery-applied `EffectiveFactView` 后才能进入 Layer 4;字段恢复子步骤不新增一套跨层事实格式。
- Validator 可以把受影响目标隔离为 Risk,但同封其他清晰目标继续到确认准备。
- 任何阶段发生可重试技术错误时记录 run attempt、错误代码和安全摘要,不伪造业务完成。
- `CONFIRMED` 是本期终点。PMS/Opera 适配器必须是后续独立状态机,不得从本状态机隐式触发。
## 4. 处理结果与隔离规则
每封邮件及每个候选目标都使用以下稳定结果类型:
| 结果 | 适用条件 | 后续行为 |
| --- | --- | --- |
| `IN_SCOPE_TASKS` | 当前邮件存在可识别的 Booking 业务目标 | 形成候选卡,经过 Validator 后进入确认 |
| `GENERAL_NOTIFICATION` | 整封 current 邮件确定没有任何支持的业务任务 | 最多一条 General 通知 |
| `RISK_NOTIFICATION` | 业务类型、目标、材料或 Parser 结果存在无法安全消解的歧义 | 每封最多一张 Risk;隔离不明确部分 |
| `IGNORED_DIRECTION` | 确定为酒店外发、内部邮件或不属于本系统处理范围 | 不创建待办任务,保留安全处理记录 |
补充规则:
- 已知业务类型但字段缺失,保留原业务类型并标记 `REVIEW_REQUIRED`,不能降格成 General 或 Risk。
- 同封邮件存在清晰任务和不清晰片段时,清晰任务继续,Risk 只承载不清晰片段。
- 重复投递、真实新邮件、revision、历史底色遗留和业务内容相同是不同判断维度;由 Validator 结合证据、消息幂等键和生命周期处理。
## 5. 固定渠道材料与 Parser 边界
### 5.1 预处理为何独立
Excel、图片和正文的原始材料体积大、结构多变且含历史内容。预处理把“能安全给 Parser/Agent 的本次材料”缩小为可定位、可审计的引用集合,因此 Agent 不必读取整张工作簿或整段会话。
- current body 和 quoted history 必须分开;quoted history 只能辅助理解、继承身份或提示重复,不可再次触发动作。
- Excel 附件保留工作簿/Sheet/行/列/底色/哈希等证据;普通任务 API 不返回整行原文。
- 图片作为 `IMAGE` 材料进入预处理。它可辅助判断 Trace、Payment/Voucher 或不在范围,但不因“有图片”自动创建业务卡。
- 无附件邮件仍经过第 1 层接入和第 4 层 Context;仅跳过 Excel 专用预处理与 Parser。
- 对 Parser fallback,信息系统可从 current subject/body 生成受控 Agent excerpt,并提取唯一明确的 Group Code 或 old→new relation 供 Context 定向查询;这不是把全文、quoted history 或附件重新交给 Agent。
- 字段解析兜底 Agent 与 Layer 5 Booking Agent 是两个不同职责:前者只收到稳定 `field_id` 及同 row/segment/room item 的最小只读上下文,不能读取或重写整份附件;后者只在 Layer 4 之后形成业务候选决定。
### 5.2 严格底色与 Profile
- 固定渠道 Profile 必须同时满足文件信号、明确业务 Sheet 规则和表头签名;平分、未知或非法 Sheet 均停止确定性解析,进入 Risk/fallback。
- `STRICT_CURRENT_CANDIDATE` 必须在 Catalog 定义的业务范围内整行非白底。字体颜色、批注、条件格式推测和白底不计入。
- anchor 行提供身份/明细列;合法 continuation 行仅补动作/状态列。任意多行互补都不能升级为确定事实。
- 未知房量保持 `booking_type=null/UNRESOLVED`,不能按 0 推断 FIT;Trace 部门只有邮件证据唯一明确时预填,否则由用户选择 FO、HSK 或二者。
### 5.3 改团号与 Trace 生命周期
- old→new 团号只在 current body 明确标注后进入 `GROUP_CODE_REPLACEMENT`;Context 只读 old/new 两个 Group Code,old 有效且 new 不存在才允许 Update 继续。两个普通团号、历史引用或多条矛盾关系均进入复核。
- 同团同封的 standalone Trace 在信息系统内合并为一张候选卡,保留每条服务项和证据;跨封 Trace 绝不并入旧卡,Context 只以无自由文本的时间序摘要提供历史顺序。
- Trace 的最终确认至少选择 `FO` 或 `HSK`,可同时选择二者;本期确认不触发部门流转。
### 5.4 运行重试与可观测性
- `FAILED` run 只能从已保存的 `PARSED_FACT_SET`、`CONTEXT_PACKAGE`、`MATERIAL_PACKAGE` 重放;不会重新拉取邮件、附件或历史,也不会创建新的 source revision。重试在 worker 中继续,processing attempt 与 `retry_count` 形成可审计的尝试链。
- `FAILED` 之外的状态拒绝重试;旧的确认投影在重试期间不返回,避免用户确认过期候选。
- 管理员只读指标固定统计最近 24 小时:失败率、Agent fallback 比率、Risk 比率、活跃积压、已重试 run 与 retry attempt。指标只来自 `th_hotel_booking` 聚合,不含个人数据、邮件内容、附件、团号或跨库查询。
- 任何监控、重试或 retention 任务都以用户确认前为终点,不能触发 PMS/Opera、付款、库存扣减或部门流转。
## 6. 数据与事实源
- 新 Booking 主线的事实源是 PostgreSQL schema `th_hotel_booking`。处理运行、版本化契约、证据引用、候选、校验和确认投影均落入该 schema。
- 旧 MySQL V4 数据仅作历史兼容读取;禁止未定义双写、跨库事务或把 MySQL 记录当作新主线事实源。
- 每次读取 Context 必须按 Group Code、订单线索或已知 SourceMessage 定向查询;无目标线索时不能扫描全库找“最像”的订单。
- 主数据(渠道白名单、sender → Account/Market/Source、Rate/Room 目录映射)也是版本化事实。目录映射由 Layer 4 `RateRoomResolver` 执行;零候选、多候选和未配置均保留待用户补充,不能让 Parser 或 Recovery Agent 猜测。
## 7. 接口与并行工作边界
后续实现可以并行,但只能依赖 contracts-v1:
- Track A:`BookingMessageOrchestrator` 和入口适配器。
- Track B:Booking Agent profile、prompt、skill/reference 与离线 contract tests。
- Track C:Context/lifecycle assembler。
- Track D:PostgreSQL repository、Flyway、主数据与 processing run。
四条线不能直接依赖对方内部 Entity、Parser 私有 record 或 AgentBus payload。共享只通过 contracts-v1 的版本化数据结构、错误码和 evidence reference。
## 8. 实施前置与验收
G1 通过条件:信息系统、Agent、Context、数据库、Validator、前端和 QA 能在不引用旧 architecture-v0.3 的前提下,只基于 contracts-v1 明确输入、输出、版本字段、状态机、结果类型和失败边界后开始实现。
与现有 V0.1 的关系:V0.1 保留为受控纵向切片和回归基线;在 contracts-v1 适配完成前,不以其旧 V4 内部结构作为新模块之间的接口。