Files
th-hotel-simple/docs/project/requirements/booking-email-architecture-v0.5.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

139 lines
10 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.5
| 项目 | 内容 |
| --- | --- |
| 文档状态 | 权威架构;V2 durable runtime本地实现,外部运行放行 HOLD |
| 架构版本 | `booking-architecture-v0.5` |
| 契约版本 | `booking-contracts-v2` |
| 决策依据 | ADR-011、ADR-012、ADR-015 |
| 业务基线 | `booking-business-agent-v1.0` |
| 范围终点 | 用户逐项确认;不调用 PMS、Opera、OHIP、付款或部门流转 |
## 1. 核心不变量
所有业务任务与处理结果的最终判断权只属于 Layer 5。字段名称相同不构成跨层授权:Layer 3 的
`SOURCE_ACTION_KIND=NEW` 仍只是来源事实,必须由 Layer 5 结合当前正文、逐来源动作、目标和 Layer 4
确定性结果重新决定是否为 `NEW_BOOKING`。历史生命周期不能改写当前任务类型。
`business_type`、`action_kind`、General/Risk/Ignored、TaskCard、linked action 和 derived action 均不得由
Layer 1–4 产生。Layer 6 不改型,Layer 7 不重算。
## 2. 七层边界
| 层 | 只负责 | 标准输出 | 禁止行为 |
| --- | --- | --- | --- |
| 1 接入 | 捕获 AgentBus/EML、身份、幂等、revision | `SourceMessageEnvelopeV2` | 看主题/来源建业务对象 |
| 2 材料 | Current/History 分离,正文、附件/图片/工作簿结构与证据;对批准的current `LLT...xlsx`只做文件名与OOXML包级安全快照 | `MaterialPackageV2` | 根据材料建任务;读取History附件、shared strings或名单明细 |
| 3 解析 | 来源事实、原始值、中立 mention/binding/relationship、材料处置和解析 issues;最终merge后追加current Rooming中立observation/binding | `Layer3ResultV2` | action hint、Booking Type、业务完整性放行、Trace/Payment/Rooming/Allotment业务判断 |
| 4 上下文 | 按 Tour Code/来源目标整理来源单元,独立解析 Roomtype;QBD 输出一项同时适用 FIT/GROUP 的 Rate 套餐方案,普通 LianTai 同时输出 FIT/GROUP 两项;把安全通过的Rooming中立材料投影为typed resolution | `DecisionContextV2.order_contexts[]`+`rooming_list_resolutions[]` | 按房量决定 Booking Type、查询数据库订单/任务历史、用历史补来源、判断重复 New/生命周期/任务顺序 |
| 5 决策 | 5A每封白名单入站调用 Booking Agent判断类型/目标;5B由信息系统复制Layer3/4固定字段并组装typed payload | `CompactDecisionV1` → `CandidateDecisionV2` | 系统替Agent做业务分类、写 TaskCard、生命周期准入、调用 PMS |
| 6 校验 | schema/evidence/目标/必填、Booking Type 对应 Rate option 等值、幂等及 review | `ValidationResultV2` | 查询生命周期/重复 New/前序任务;新增或替换业务类型、重算 Candidate |
| 7 展示确认 | 一对一展示 Candidate+Validation,接受逐项确认 | `ConfirmationProjectionV2` | 聚合/解释/重算业务参数、执行 PMS |
## 3. 唯一 Layer 5 调用边界
```text
SourceMessageEnvelopeV2
→ MaterialPackageV2
→ Layer3ResultV2
→ DecisionContextV2
→ BookingDecisionInputV2 (canonical JSON + SHA-256)
└─ short transaction: persist Layer3/4/input + enqueue one execution
→ COMMIT / AWAITING_BOOKING_AGENT
→ durable worker claim (lease + fencing)
└─ outside database transaction
├─ Booking Business Agent (compact input → compact business decision)
├─ expected platform Profile ID gate + published version audit
└─ Layer 5B deterministic Candidate assembler + strict decoder / fail-closed Risk
→ short transaction: persist one CandidateDecisionV2
→ recoverable Layer6 claim → ValidationResultV2
→ ConfirmationProjectionV2 / validated V4 compatibility projection
```
白名单入站邮件每封只建立一个Booking Agent业务execution并只接受一份有效Candidate;临时网络故障可在同一
execution内进行有限Provider attempt,不能产生第二份业务结果。New/Update/Cancel/General也不得由本地规则提前返回。Facade
向 Agent 发送专用精简投影,而不是完整内部对象:保留 Current、完整有序邮件 History 正文、按物理行组织的必要事实、
Layer 4解析状态和当次短引用,排除完整Layer3技术包装、evidence registry、History附件、数据库订单/任务历史和生命周期准入结论。
Agent只判断业务;Layer 5B再从canonical输入复制日期、房型、数量、价格、对应Rate/早餐和证据。每个 run 只保存一个权威
Candidate;shadow 结果只能作为
不可写比较 artifact。
确定性组装器校验同一 run/message/revision/version,保留 Layer3ResultV2,不覆盖来源事实,按显式
`source_unit_ref/room_item_ref` 绑定,并以稳定顺序合成唯一 `BookingDecisionInputV2`。Layer 4 不查询数据库;
来源字段缺失直接形成 null/`UNRESOLVED`,由后续人工确认。
## 4. 业务类型与关系
- New/Update/Cancel:Agent 根据当前来源动作/正文和目标识别;类型与目标明确后字段缺失仍保留原类型。
Booking Type 由 Layer 5 按独立订单有效房量 1–4 FIT、5+ GROUP;确定后只能使用对应 Layer 4 Rate option。
本期不自动检查重复 New 或生命周期资格。
- Trace:Layer 3 structured mention 仅是来源语义;Booking Agent 决定是否形成 Trace、服务项和部门候选。
- Rooming List:Layer 2/3只按current完整`LLT...xlsx`文件名和OOXML包级安全结构形成中立材料;Layer 4安全通过
才给Excel/标签/唯一Tour Code typed resolution。Agent只消费该resolution,不读取文件内容,业务判定仍在Layer5。
- Payment:本期不是业务类型,只作为未归类原文。
- Allotment:target business type 不含 ALLOTMENT。只有当前正文明确 Allotment 操作时处理;定量 source
deduction 按符合条件的物理目标行独立派生,不聚合、不查 old/remaining;整块取消按唯一 source 一项。
- General 是可与任务并存的未归类原文区;Risk 按不明确事项局部隔离;Ignored 只作错误方向安全兜底。
- 单目标业务关系使用 typed `linked_actions[]`;跨目标共享效果只用 `derived_actions[]`。
## 5. Current、History、附件与安全
内部 `BookingDecisionInputV2` 与 Agent 输入都保留 Current 和有序邮件 History 正文。Agent 专用输入只提供当前
附件说明、按单元整理的必要Layer3/4业务材料和当次短引用;完整evidence registry、History附件、数据库订单/任务历史和生命周期结论不进入。
输入不包含附件二进制/Base64、签名 URL、Cookie、Secret、数据库连接或隐藏推理。外部 Agent adapter 必须从同一
canonical对象确定性投影compact输入;短引用只在本次调用有效,不能成为第二个事实来源。
文件名型Rooming附件不会进入Parsing Agent request,其文件名、bytes与内容均排除。信息系统仅在本地保存
隐私最小化snapshot和Evidence;History附件仍完全不读取。名单内容Parser是独立能力,本链不调用。
Roomtype 只按来源房型精确映射;Rate 使用目录公司、显式 option 类型、来源房型、来源价格和早餐条件,严禁使用
canonical Roomtype。Rate 唯一性按不同 `{Rate Code+早餐+餐厅}` 套餐计算。同一 Tour Code 内每个 option
分别收敛;普通 LianTai 两项同时输出,Layer 5 判断 Booking Type 后选中对应项。来源缺失不触发历史查询。
## 6. Validator、展示与确认
- Layer 6 对 target 和 derived action 独立返回 `VALID/REVIEW_REQUIRED/RISK/REJECTED`,并保持 Candidate
canonical hash 不变。
- derived action 被阻断时,不回滚其他已通过的 target。
- Layer 7 只显示 Layer 5 已给出的逐物理行 source deduction/whole cancel 和 Layer 6 状态,不计算库存余额。
- 确认按 item 幂等。部分 target 已确认而 derived action 仍 review 时,run 为 `PARTIALLY_CONFIRMED`。
## 7. 入口、持久化与迁移
- Manual EML 与 AgentBus 始终先落 SourceMessage,并进入同一 persistence-neutral orchestrator。
- PostgreSQL/MySQL 只是 Port 实现,不决定是否走 Layer 5。
- 最终Layer3、Layer4、canonical input、唯一Booking Agent execution和`AWAITING_BOOKING_AGENT`必须在短事务中
提交;任何Provider网络等待都必须发生在事务外,失败不得回滚已完成的Parsing结果。
- V11 execution使用稳定input-hash幂等、`SKIP LOCKED`、lease/fencing和有限退避;Candidate单独提交后是Layer6
的恢复点,重启或重复唤醒不得重呼Provider或生成不同Candidate。
- 每个Provider attempt写受控审计;raw回答不落库。不可重试契约错误和重试耗尽形成安全Risk Candidate,仍须
进入Layer6,不能直接创建任务。
- 新 V4 Booking TaskCard 只允许从 validated v2 projection 创建,并保存 run/candidate/validation provenance。
- v1/V4 历史数据只读;新运行不写 `action_hint/booking_type` lower-layer business hints,不做批量回填。
- `SHADOW` 只比较不写业务,`AUTHORITATIVE` 独占写入,`CAPTURE_ONLY` 只捕获并产生安全 Risk/review。
- 切换或回退不得恢复 legacy Parser/Agent 直接建卡。
## 8. 运行状态与放行边界
```text
RECEIVED → MATERIAL_READY → PARSER_COMPLETE → CONTEXT_READY
→ AWAITING_BOOKING_AGENT → BOOKING_AGENT_IN_PROGRESS
→ [BOOKING_AGENT_RETRY_WAIT → BOOKING_AGENT_IN_PROGRESS]*
→ BOOKING_AGENT_CANDIDATE_RECEIVED → LAYER6_VALIDATING
→ VALIDATED → AWAITING_CONFIRMATION
→ PARTIALLY_CONFIRMED | CONFIRMED
```
重试耗尽先暴露`BOOKING_AGENT_RETRY_EXHAUSTED`,不可重试Candidate错误先暴露
`BOOKING_AGENT_CANDIDATE_REJECTED`;二者随后都持久化安全Risk并进入Layer6。真实Provider当前Profile复核、
Booking PostgreSQL V1–V11、非生产live chain、production authoritative切换和PMS/Opera/OHIP均需独立审批,
本架构文档不构成发布授权。
## 9. 替代关系
- 本文、`booking-business-agent-rules-v1.md` 与 `booking-email-contracts-v2.md` 是新运行的权威基线;业务语义
以 rules-v1 为准,wire shape 以 contracts-v2 为准。
- architecture-v0.4/contracts-v1 仅用于历史 artifact/V4 读取和迁移回归,不再定义新业务写入边界。
- M002/M012/BR00 旧实现记录若与 ADR-012 冲突,以 ADR-012、rules-v1 和本架构为准;旧 payload 不回写。