Files
th-hotel-simple/docs/project/requirements/M012-qbd-liantai-parser-output-contract-v1.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

15 KiB
Raw Blame History

M012 / QBD+LianTai Parser 输出冻结契约 v1

项 内容
状态 FROZEN — USER CONFIRMED;PARSER IMPLEMENTED;REAL-SAMPLE CORRECTIONS ACCEPTED
日期 2026-08-11
契约名称 fixed-channel-parser-fact-material-v1
适用渠道 QBD、LianTai
不在范围 其他 sender、Parsing Agent 完整输出 schema、Rate/Room、TaskCard、PMS/Opera
变更规则 冻结后只能通过新 ADR 和新 contract version 修改

1. 给业务人员看的结论

Parser 每次处理一份工作簿,只交付:

  1. 本次处理是否正常完成;
  2. 程序已经确认的业务信息;
  3. 程序看到了、应该继续处理、但无法确认的原文。

程序不再输出“缺失、未解决、歧义、冲突、原因代码”等分类。

2. 顶层输出

{
  "meta": {},
  "status": "SUCCESS",
  "facts": [],
  "agent_materials": []
}
字段 必填 业务含义
meta 是 来源文件、渠道 Profile 和版本等追踪信息
status 是 SUCCESS 或 FAILED
facts 是 已经形成唯一确定值的事实,允许空数组
agent_materials 是 需要继续处理的原始材料,允许空数组

业务结果只有 facts 和 agent_materials 两类。meta/status 只是运行外壳。

3. meta 冻结字段

{
  "parser_result_id": "pr_xxx",
  "source_message_id": "msg_xxx",
  "attachment_id": "att_xxx",
  "attachment_content_hash": "sha256:...",
  "file_name": "QBD月表.xlsx",
  "profile_code": "QBD",
  "contract_version": "fixed-channel-parser-fact-material-v1",
  "parser_version": "1.0.0",
  "profile_version": "1.0.0",
  "rule_bundle_version": "1.0.0"
}

profile_code v1 只允许:

QBD
LIANTAI

文件名只用于描述和审计,不参与渠道业务判断。

4. facts[] 冻结字段

{
  "fact_id": "fact_xxx",
  "fact_key": "target_1/room_1/SOURCE_ROOM_NAME/CURRENT",
  "target_ref": {
    "target_id": "target_1",
    "row_unit_id": "row_12",
    "segment_id": "segment_1",
    "room_item_id": "room_1"
  },
  "semantic_role": "SOURCE_ROOM_NAME",
  "material_state": "CURRENT",
  "value_type": "STRING",
  "raw_value": "ONE-BEDROOM-SUITE TWN BF(Q10)",
  "normalized_value": "ONE-BEDROOM-SUITE TWN BF(Q10)",
  "source_locations": [],
  "rule_ref": "shared-source-room-name-v1"
}
字段 必填 说明
fact_id 是 本条事实的稳定唯一 ID
fact_key 是 合并时识别同一事实槽位的稳定键;由 target、role、state 构成
target_ref 是 事实属于哪一业务行、住宿段和房型项;不适用的下级 ID 为 null
semantic_role 是 本契约允许的业务事实类型
material_state 是 CURRENT、BEFORE 或 AFTER;fact 不允许 MIXED
value_type 是 STRING / INTEGER / DECIMAL / DATE / BOOLEAN / JSON
raw_value 否 来源中的原始值;确定性默认值允许为 null
normalized_value 是 Parser 依据冻结规则形成的唯一规范值
source_locations 是 一个或多个可复核来源位置,不允许空
rule_ref 是 形成该事实的确定性规则引用;不是失败原因代码

facts 内不存在独立的状态、缺失标志或 reason code。fact 存在本身就表示该值已确定。

5. 冻结的十类业务事实

semantic_role 给业务人员的含义 v1 规则摘要
GROUP_CODE 团号/预订目标代码 统一承接 Tour Code、Group Code 等已确认来源别名
SOURCE_ACTION_DATE 来源动作指令日期 只表示表格指令写出的日期,不是处理时间或入住日期
SOURCE_ACTION_KIND 来源动作类型 规范值只允许 NEW_BOOKING / UPDATE_BOOKING / CANCEL_BOOKING;原始细分文字保存在 raw_value
ARRIVAL_DATE 入住日期 必须由当前材料和 Profile 日期规则唯一确定
DEPARTURE_DATE 离店日期 必须由当前材料和 Profile 日期规则唯一确定
NIGHTS 晚数 入住、离店均确定后按日期差确定;不跨住宿段累加
SOURCE_ROOM_NAME 完整来源房型名称 保留 BF、Q10、FAM/PAX、床型、景观等来源含义
BREAKFAST_INCLUDED 来源明确声明的早餐条件 独立 BF=true;明确 RO/不含早=false;未声明时不生成该事实
ROOM_QUANTITY 房间数量 明写数量按原文;Profile 已冻结的“缺数量默认 1”可生成事实并保留 rule ref
SOURCE_PRICE 来源价格 只有来源价格存在且能按冻结规则唯一规范化时生成

以下内容不属于 Parser v1 公共事实:

GROUP_IN
SOURCE_RATE_CODE
ROOM_QUALIFIERS
BOOKING_TYPE
canonical Room / Rate Code
Allotment source/actual relationship
最终业务事件
Trace / 普通备注的最终业务处置
TaskCard / 部门 / PMS或Opera执行状态

6. 完整来源房型名称、BF 与 Q10

6.1 不拆 Q10

原文:

ONE-BEDROOM-SUITE TWN BF(Q10)

正确输出:

SOURCE_ROOM_NAME = ONE-BEDROOM-SUITE TWN BF(Q10)
BREAKFAST_INCLUDED = true

错误输出:

SOURCE_ROOM_NAME = ONE-BEDROOM-SUITE TWN
ROOM_QUALIFIERS = Q10

6.2 允许的规范化

raw_value 保留准确来源文本。normalized_value 可以统一大小写、重复空格和无业务含义的连字符差异, 但不能删除或拆分 BF、Q10、ONE/TWO-BEDROOM、DBL/TWN/TRP、FAM/PAX、U、GARDEN/POOL/VIEW 等业务区分项。

若数量或价格与房型名称紧邻,只有在 Profile 规则能唯一证明它们分别属于数量/价格时才允许拆出; 拆出后仍不得破坏完整来源房型名称中的 BF/Q10 语义。

6.3 早餐

  • 出现独立 BF 标记:BREAKFAST_INCLUDED = true。
  • 出现明确 RO 或“不含早”:BREAKFAST_INCLUDED = false。
  • 两者均未出现:不生成 BREAKFAST_INCLUDED,不得把未声明解释为不含早。
  • Q10 与早餐判断无关。
  • 输出早餐布尔值时,不能从 SOURCE_ROOM_NAME 中删除 BF。
  • 公共字段结构仍为 v1;本次语义通过 shared-breakfast-explicit-token-v2 规则引用版本化,不新增字段。

7. agent_materials[] 冻结字段

{
  "material_id": "material_xxx",
  "target_ref": {
    "target_id": "target_1",
    "row_unit_id": "row_12",
    "segment_id": "segment_1",
    "room_item_id": "room_1"
  },
  "expected_fact_keys": [
    "target_1/room_1/SOURCE_PRICE/CURRENT"
  ],
  "material_state": "CURRENT",
  "material_kind": "WORKBOOK_TEXT_SPAN",
  "raw_content": "【U-DBL1.2/1.3】",
  "context": {
    "header": "房型及价格",
    "neighboring_cells": ["2间", "含早"]
  },
  "source_locations": []
}
字段 必填 说明
material_id 是 待处理材料的稳定唯一 ID
target_ref 否 能安全定位所属目标时填写;不能猜测
expected_fact_keys 是 已知待解决事实槽位时填写;整表兜底时允许空数组
material_state 是 CURRENT / BEFORE / AFTER / MIXED
material_kind 是 ATTACHMENT / SHEET / ROW / CELL / TEXT_SPAN
raw_content 是 原文、结构化单元格内容或受控附件引用
context 是 Agent 理解该材料所需的最小表头、相邻值和格式上下文;允许空对象
source_locations 是 一个或多个准确来源位置,不允许空

agent_materials 不包含:

MISSING
UNRESOLVED
AMBIGUOUS
CONFLICT
reason_code

每个 material 应尽量对应一个待决事实问题;可以带更宽的只读上下文,但不能成为无边界原文垃圾桶。

8. 共用来源位置

{
  "attachment_id": "att_xxx",
  "sheet_name": "2026.08",
  "row_number": 12,
  "cell_ref": "F12",
  "text_start": 0,
  "text_end": 15,
  "formatting_signature": "fill:#FFFF00",
  "content_hash": "sha256:..."
}

不适用的细粒度位置字段可为 null,但 attachment ID、content hash 和能够达到的最精确位置必须存在。 不得在结果中嵌入附件 URL、Secret 或附件二进制/Base64。

9. 唯一判断规则

Parser 按事实槽位判断,不按整行或整格一刀切:

  1. 唯一规范值成立:输出 fact。
  2. 有原文但不能唯一确定:不输出该 fact;输出 agent material。
  3. 来源中完全没有该内容:fact/material 都不输出。
  4. 同槽位多个来源给出相同规范值:输出一个 fact,并保留全部来源位置。
  5. 同槽位存在不同规范值:不选择任何一个作为 Parser fact;保留全部相关原文为 material。

例如 【U-DBL1.2/1.3】2:若房型和数量可以唯一确认,Parser 输出 SOURCE_ROOM_NAME = U-DBL 与 ROOM_QUANTITY = 2;价格原文进入 material,不生成 SOURCE_PRICE。

10. SUCCESS / FAILED

SUCCESS

表示 Parser 正常结束且结果可信,不表示“所有字段齐全”。以下均合法:

facts有值,agent_materials为空
facts有值,agent_materials有值
facts为空,agent_materials有值
facts为空,agent_materials为空(工作簿中没有本期业务行)

能安全读取但不支持的版式、多个候选业务表或无法唯一识别的业务区域,使用 SUCCESS 并把必要的 Sheet/Row/Attachment 材料交给 Agent,不改成歧义状态。

FAILED

只用于结果无法被信任的技术失败,例如:

  • 文件损坏、加密或无法安全读取;
  • 文件大小/安全限制;
  • Parser 未处理异常;
  • 结果身份、来源定位或序列化契约无法成立。

FAILED 时 facts 必须为空,不发布部分事实。原始附件仍由外层 SourceMessage/Attachment 记录保留, 由外层流程进入失败复核或受控兜底;Parser 不伪造材料内容。

11. 合并结果边界

本契约同时冻结合并结果的两类顶层业务内容:

{
  "effective_facts": [],
  "review_items": []
}
  • Parser facts 不可被 Agent 覆盖。
  • Agent 只能基于获准的 agent material 补充候选事实。
  • 同一事实键同值可以合并来源;不同值不得静默覆盖,进入 review。
  • 每个 agent material 最终必须被接受事实覆盖,或进入 review,不能静默消失。
  • 必需事实完全缺失时,由合并后的完整性校验产生 review,不由 Parser 伪造材料。

Parsing Agent 自身的完整输入/输出字段和 review item 的展示分类不在本 Parser 契约中冻结,后续单独确认。

12. Core 与 Profile 边界

共享 Parser Core

  • 输出结构、版本和运行状态;
  • fact/material 稳定 ID、事实键和 target 结构;
  • “唯一值才形成事实”的门禁;
  • 来源位置与上下文封装;
  • 结果 schema 校验。

Core 提供一个只供 Profile 使用的原始材料入口。Profile 交入业务行、整段原文、上下文和证据位置,Core 统一生成正式 agent_materials。备注类材料固定为 CURRENT,expected_fact_keys=[],上下文固定包含 material_purpose=USER_REMARK、source_column,能取得表头时还包含 source_header。Core 必须验证材料 引用的业务行、来源消息、附件、Sheet、行号和单元格都与已登记证据一致;任一不一致时 Parser 整体 FAILED,不发布部分结果。

QBD / LianTai Profile

  • 工作簿、Sheet、表头和业务行识别;
  • 渠道列位、底色、rich text 和模板噪音;
  • 日期、来源动作、房型、数量和价格语法;
  • Profile 确定性默认规则。

Profile 允许内部临时拆分 BF、Q10、价格 token 或 QBD GROUP IN 单元格,但公共输出必须重新符合本契约; 内部字段不得泄漏成第十一类公共事实。

QBD Profile 补充规则:

  • WAITING 等待确认 / อักษรดำ 是可选备注列,按表头文字识别,不固定为 K 列;只在核心表头行及其紧邻 上一行寻找。没有该列不影响旧模板;同一表头带出现多个候选时不得猜测,走既有附件级兜底材料;
  • WAITING 不参与业务行选中。只对已经选中的有色业务行读取非空单元格,每格整段原文形成一条备注材料; 空格不生成任何输出,2300 THB 等内容不得拆数字、解释为价格或生成 SOURCE_PRICE;
  • 每个物理明细行先按完整“房型+数量”块判定状态。所有块均划线时,该行日期、晚数、房型、数量都属于 BEFORE;所有块均未划线且同一业务行已有修改前内容时都属于 AFTER;没有修改前内容时仍为 CURRENT。不同房型块状态不一致或单块内部混合时保持 MIXED,不强行生成整行日期事实;没有房型块时 沿用整行格式判断。

LianTai Profile 补充规则:

  • G、I 列完整原文及 D 列完成确定性字段提取后的残余原文,均通过上述共享入口形成备注材料;
  • G 列已经唯一形成的 SOURCE_ACTION_DATE、SOURCE_ACTION_KIND facts 继续保留,完整 G 原文可以同时 作为补充材料保留;旧内部 classification_status、reason code 等状态不得进入公共结果。

13. 迁移与验收门禁

本契约冻结时,现有代码仍使用旧 FieldObservation、多状态和 Recovery Patch 模型。2026-08-11 已完成 Parser-only 迁移切片,实施状态如下:

  1. 已以本契约替换 QBD、LianTai 和共享入口的默认 parse 公共 DTO;
  2. 目标输出已移除旧公共状态、reason code、GROUP_IN、SOURCE_RATE_CODE、ROOM_QUALIFIERS;
  3. 完整来源房型名称与 BF/Q10 规则已进入双渠道共享契约测试;
  4. 十类 facts、部分确定、完全缺失、材料冲突、SUCCESS/FAILED 已有契约测试;
  5. 真实样本缺口已修正并回放通过:QBD 为 114 facts、4 条 WAITING materials,rows 118/121 的 BEFORE/AFTER 日期、晚数、房型和数量完整;LianTai AI 样板为 70 facts、6 materials,其中 G 列 5 条、 I 列 1 条。公共 DTO 与十类 fact 目录未改变;
  6. Parsing Agent v1.0 已由独立 ADR-009 冻结;CP4 已接通默认关闭的 runtime/merge/fake链。旧 observation/Recovery只保留在显式 parseLegacy 兼容桥,尚未删除;
  7. 本次没有启用 Provider、AgentBus Recovery、PMS、Opera 或生产功能。

14. 权威性

对 QBD/LianTai Parser 公共输出,本文件与 ADR-008 的优先级高于:

  • ADR-001 的字段 Recovery 公共边界;
  • ADR-007 的旧 observation/Field Recovery 兼容描述;
  • C03-v2 Draft 的多状态 contribution core;
  • 旧 QBD/LianTai Parser CR 中的 observation status、reason code 和内部拆分字段。

历史文档继续保留用于说明当前代码和迁移来源,不得再作为新 Parser 输出的实现依据。