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

13 KiB
Raw Blame History

Booking 邮件处理架构 v0.4

迁移状态(2026-08-13):本版本仅用于旧 V4 读取和迁移回归。它曾配套的 CandidateDecision v1 正式契约 从未上线且已删除。新运行只以 v0.5、 contracts-v2 和 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)使用以下状态;状态是运行主线,不等同于单张业务卡的用户可见状态:

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 内部结构作为新模块之间的接口。