Files
Wyndham-RSVN/docs/project/requirements/booking-email-contracts-v1.md

13 KiB
Raw Blame History

Booking 邮件 contracts-v1

项目 内容
文档状态 权威契约
契约版本 booking-contracts-v1
对应架构 Booking 邮件处理架构 v0.4
适用终点 用户确认PMS/Opera 不在本契约执行范围

1. 共同信封与版本规则

七层之间传递的每个顶层对象必须包含 contract_metaevidence_refs[]。禁止靠调用方上下文、数据库隐式默认值或 Agent prompt 隐式补齐版本。

字段 必填 说明
contract_version 固定 booking-contracts-v1。不兼容变更必须新版本。
catalog_version 本次使用的业务目录版本;尚未执行目录处理时填 catalog-not-applied
parser_version 本次 Parser 版本;未执行时填 parser-not-run
agent_profile_version Booking Agent profile 版本;未调用时填 agent-not-invoked
processing_run_id 一次处理运行的稳定 ID重试使用同一 run、不同 attempt。
source_message_id 平台 SourceMessage 的稳定 ID不可使用邮件主题代替。
source_revision 同一来源消息在材料重取或重放后的可追溯版本。
evidence_refs 最小化证据引用不嵌入原始邮件、完整附件、Secret 或外链 URL。

evidence_ref 至少包含 evidence_idkindsource_message_idlocatorcontent_hashis_current_materialkind 允许 CURRENT_BODYQUOTED_HISTORYATTACHMENTWORKBOOK_SHEETWORKBOOK_ROWIMAGEOCR_TEXTCONTEXT_RECORDUSER_CORRECTIONlocator 只能表达安全定位(例如 Sheet/行号、附件逻辑 ID、上下文记录 ID不能含签名 URL 或原文全文。

所有 issue 使用同一结构:codeseverityINFO/WARNING/BLOCKER)、scopeMESSAGE/MATERIAL/TARGET/FIELD)、message_keyevidence_refs[]、可选 retryable。用户可见文本由 message_key 和前端文案生成,避免把原文写进 API。

2. SourceMessageEnvelope

层 1 输出。 统一 AgentBus 与手工 EML不携带业务判断。

字段 说明
message_origin AGENTBUSMANUAL_EML
external_message_idconversation_idin_reply_to 邮件身份与会话链路;缺失时保留 null不用主题猜。
idempotency_key 基于可信消息身份/内容摘要形成;只处理外部重复投递,不合并两封真实邮件。
senderrecipientssubject 最小化安全摘要或受控引用;不作为唯一业务事实。
received_at 收件时间点UTC
current_body_refquoted_history_ref 对正文 current/history 分离后的证据引用。
attachment_descriptors[] 逻辑附件 ID、文件名摘要、媒体类型、大小、内容哈希、受控原件引用。

不可接受:入口直接调用 Parser/Agent 后跳过 SourceMessage、入口把 AgentBus 的原始 JSON 当领域对象、或根据邮件主题创建订单。

3. MaterialPackage

层 2 输出。 描述可供解析/理解的材料,不表达最终业务类型。

字段 说明
message_envelope SourceMessageEnvelope 的最小必要摘要与 ID。
current_materials[] 本次可触发业务的 current body、当前附件、当前图片、明确版本指令。
quoted_history_materials[] 仅用于解释、继承身份、重复检查的历史材料。
workbook_inspections[] 文件哈希、Sheet 名称、表头签名、候选行/列、底色证据、Profile 候选与检测结果。
image_inspections[] 图片证据与可选 OCR 安全摘要;不把 OCR 当唯一事实。
material_selection_status READYNO_ATTACHMENTUNSUPPORTEDAMBIGUOUSFAILED
issues[] 材料层问题,例如超限、文件损坏、多个 Profile 平分、非法 Sheet。

规则current 与 quoted 必须可区分;没有附件时输出 NO_ATTACHMENT 但仍为有效 package固定渠道只把严格候选行送入确定性 Parser其他行只能作为复核证据。

4. ParsedFactSet

层 3 输出。 Parser 的标准事实集合;它不等于最终业务决定。

字段 说明
parser_applicability APPLICABLENOT_APPLICABLEFAILEDAMBIGUOUS
channel_profile_code 成功解析时的固定渠道 Profile不能唯一确定时为 null。
facts[] 可追溯的标准事实,必须逐项带 fact_idconfidence_kind=DETERMINISTICevidence_refs[]
unresolved_fields[] 未能确定的字段及原因未知房量、Rate Code 映射等必须保留。
fallback_reasons[] 需要 Booking Agent 或 Risk 的明确原因代码。
issues[] Profile、底色、字段格式、解析失败等问题。
agent_input_material 可选、受控的 Agent current-message 文本;只在本地 policy 脱敏、限长后出现。

facts[] 的稳定字段包括:

  • action_hintNEW_BOOKINGUPDATE_BOOKINGCANCEL_BOOKING 或 nullbooking_type 只在房量足以确定时为 FIT/GROUP,否则为 null。
  • target_identitygroup_code 是团号统一字段;Name of GroupGroup NameTour CodeGroup Code 进入该字段。group_name 只用于邮件明确给出的独立展示名称;tour_code 是历史兼容镜像,不能与 group_code 形成两个目标。name_values 只保存真正的客人/联系人姓名;字段未知必须为 null。
  • stayarrival_datedeparture_datenightsroom_items[]、价格原始证据。
  • room_items[]room_type_code_hintroom_countrate_hintevidence_refs[]Extra Bed 不能写入房型。
  • related_hints[]Trace、Rooming List、Payment、Allotment source/actual、明确 GROUP_CODE_REPLACEMENT old→new 关系等候选线索。

agent_input_material 是为了让 Parser fallback 能理解无固定渠道的正文,而不是第二份原始邮件:它只能绑定一个 CURRENT_BODY evidence内容仅来自 current subject/bodybooking-agent-current-message-v1 脱敏并限制为最多 12,000 个 code point。它必须排除 quoted history、原始附件、附件 URL、sender 原文和 Secret该受控摘要可随 PARSED_FACT_SET 在项目 schema 保留至 retention_until,以支持同一 run 的异步 Agent/retry不得用它还原原始邮件。

GROUP_CODE_REPLACEMENT 只接受 current body 中明确标注的 old→new 指令。单封普通文本中出现两个团号、主题猜测或 quoted history 都不能生成关系。该 relation 在 Parser fallback 中是无动作 Context/Agent clue固定渠道仅能绑定到同一 new group code 的 UPDATE_BOOKING fact。

Parser 不得:将 room_count=0 解释为 FIT、在 Profile 平分/未知/非法 Sheet 时产生确定事实、用多行互补制造 anchor 事实、或因字段缺失把已知动作改写成 General/Risk。

5. ContextPackage

层 4 输出。 面向一封当前邮件与已识别目标的最小上下文,而不是历史全量 dump。

字段 说明
context_scope MESSAGE 或一个/多个 TARGET;每个 target 有独立查询边界。
target_resolutions[] 输入线索、零/一/多候选、解析状态和证据;多候选不自动选择。
current_state 已确认事实、有效未完成任务、计划完成态;带数据来源与更新时间。
conversation_context 当前邮件的必要历史摘要、revision 关系与重复线索;历史内容不重新触发动作。
lifecycle_context New/Update/Cancel 前置链、old→new Group Code、Cancel 后冲突、Trace 顺序。
allotment_context source 团与 actual 团候选关系、库存/扣减可用性;不是最终扣减命令。
issues[] 上下文缺失、多目标冲突、历史证据冲突等。

读取规则:优先 Group Code、明确订单 ID、已确认消息关联无可靠目标时返回未识别而不是全文/全库模糊扫描。

GROUP_CODE_REPLACEMENT 存在时Context 必须只读取 old/new 两个明确 Group Codeold 有效已确认链且 new 不存在才是 RESOLVEDold 已取消/不存在为 UNRESOLVEDnew 已存在为 CONFLICTgroup_code_replacements[] 必须保留 relation ID、old/new、状态、候选 ID 和 issue。Trace 历史按 Group Code 和时间顺序只提供安全摘要(任务 ID、状态、FO/HSK、服务类型跨封 Trace 永远是新卡,历史自由文本、附件定位和 quoted 内容不能进入 Context。

6. CandidateDecision

层 5 输出。 可以来自纯确定性合成或 Booking Agent两者使用同一结构。

字段 说明
decision_origin DETERMINISTICAGENTMIXED
result_disposition IN_SCOPE_TASKSGENERAL_NOTIFICATIONRISK_NOTIFICATIONIGNORED_DIRECTION
target_decisions[] 每个目标独立的候选动作、目标身份、字段、linked/derived actions、证据和 issues。
message_notifications[] General/Risk/ignored 的消息级结果Risk 每封最多一条。
agent_trace_ref Agent 调用 ID/版本/安全摘要;纯 Parser 时为空。
issues[] 对整封消息的无法分配问题。

target_decisionbusiness_type 为:NEW_BOOKINGUPDATE_BOOKINGCANCEL_BOOKINGTRACE_RESERVATION_NOTESROOMING_LISTPAYMENTALLOTMENTaction_kind 由业务类型和当前态决定。Allotment 必须显式输出 actual 与 source 的关联,不能把多个 actual 或 source 扣减隐匿在一张普通 New 卡里。

Booking Agent 的受控输入只允许 ParsedFactSet + ContextPackageParsedFactSet.agent_input_material 是唯一可见的正文材料,且受上文 policy 约束。若 Parser NOT_APPLICABLEFAILED,也必须先创建最小的 ParsedFactSet,明确未解析原因,而不是把原始附件或 quoted history 直接交给 Agent。

7. ValidationResult

层 6 的校验输出。 只有 validation_status=VALID 的目标才可产生确认投影。

字段 说明
validation_status VALIDREVIEW_REQUIREDRISKREJECTED
validated_targets[] 目标级通过/阻断结果,不让一个目标阻断同封其他清晰目标。
schema_checks[] contracts-v1 结构和版本检查。
business_checks[] Catalog、必填、目标、生命周期、前置任务、linked action、重复/revision 检查。
blockers[] 必须由用户补齐或修复才可确认的条目。
risk_notification 仅隔离无法安全决定的部分;每封至多一张。

Validator 必须校验版本一致性、证据存在、目标解析、字段必填、Catalog 映射、当前生命周期、已确认/未完成任务、外部重复投递、真实新邮件、revision、历史底色遗留和业务内容相同。Agent 输出无效时,目标级进入 Risk不能绕过 Validator 建卡。

8. ConfirmationProjection

层 6 面向前端的安全输出。 它不是原始 CandidateDecision 的直通 JSON。

字段 说明
projection_status AWAITING_CONFIRMATIONREVIEW_REQUIRED 或不可生成。
confirmation_items[] 用户可见任务/通知,按目标拆分。
display_fields[] 已归一化的关键字段、展示值、来源证据、可编辑性与校验规则。
blocked_fields[] 缺失/冲突字段及需用户选择的候选;不暴露内部 payload。
linked_actions[] 如 Allotment source/actual、Trace 合并关系;只显示本期可确认参数。
safe_evidence[] 文件/Sheet/行/图片等安全引用与脱敏摘要。
processing_run run ID、当前状态、可重试状态与安全错误摘要。

确认 API 只冻结用户确认的参数和审计,必须携带 processing_run_id 与并发版本。确认成功不调用 PMS/Opera也不执行付款、库存扣减或部门流转。

9. 编排、持久化与 API 约束

  1. AgentBus 与手工 EML 都调用同一个 BookingMessageOrchestrator,并产生一致的 SourceMessageEnvelope 幂等语义。
  2. 同步完成且无需异步 Agent 时返回 201;进入 Agent 或异步处理时返回 202processing_run_id
  3. 状态查询为 GET /api/reservation/booking-processing-runs/{runId};已有 POST /api/reservation/booking-email-intakes 逐步适配为统一入口。
  4. PostgreSQL th_hotel_booking 保存 run、attempt、版本、证据引用、候选、校验和确认投影PARSED_FACT_SET 中只允许保存受 policy 约束的 Agent 摘要,所有这些项目 schema 数据按 retention_until 三个月清理。旧 MySQL 只能被 Context 兼容读取,不能参与新主线写入或跨库事务。
  5. 所有持久化/接口代码必须使用 contract_version 做版本门禁;未知未来版本 fail closed 并形成安全 Risk/技术错误记录。

10. 兼容与测试要求

  • Parser 与 Booking Agent 对相同事实必须输出可比较的 CandidateDecision;差异只能通过显式 decision_origin 和 issue 表达。
  • 每个 Contract 都需 JSON/Java fixture、schema validation、正向/错误案例及 evidence reference 检查。
  • 真实邮件只作为 opt-in 外部验收;仓库只保存去隐私 fixture 与样本哈希/Profile 断言。
  • 后续对字段、枚举、状态机或业务动作做破坏性变更时,必须新增 contracts-v2而不是静默改 v1。