Complete the selective V2 checkpoint with its minimal AgentBus, object-storage, replay persistence, and validated-workbench shared dependency closure.
9.1 KiB
M012 / Layer 3 当前 Rooming List 文件名材料识别 Change Request v1
| 项 | 内容 |
|---|---|
| 状态 | LOCAL IMPLEMENTATION ACCEPTED;真实 Provider/生产发布继续 HOLD |
| 日期 | 2026-08-13 |
| 目标 | 只按当前 .xlsx 附件文件名识别 Rooming List 中立材料,并接入现有 Layer 3/4 契约 |
| 渠道 | QBD、LIANTAI;不含 LIANTAI_FIT |
| Checkpoint | M012-layer3-current-rooming-list-filename-material-v1 |
| 发布边界 | 不调用真实 Provider、数据库、PMS/Opera;不授权 CP5/CP6 |
1. 背景与目标
CP4 已把公共 Parser、Parsing Agent v1 本地合并结果直接接入最新 Layer3ResultV2。当前缺口是:固定渠道
邮件同时携带 Rooming List 时,信息系统尚未把该附件作为独立中立材料传到 Layer 4
rooming_list_resolutions[],并且额外工作簿会影响 QBD/LianTai 月度更新 Parser 的唯一附件门禁。
本 Change Request 增加一个信息系统内的确定性材料识别器。它只确认附件文件名、文件身份与安全结构,不读取 名单业务内容。Layer 5 Booking Agent 继续独占“是否属于 Rooming List 业务、是否创建候选/任务”的判断权。
2. 职责边界
Layer 3 允许输出:
- 哪个当前附件命中 Rooming List 文件名标签;
- 文件名提取出的 Tour Code 候选及是否唯一;
- 当前附件与 Tour Code 的中立 binding;
- 文件身份、安全结构检查结果、原因码与 Evidence;
- 无法安全读取时的中立未解析结果。
Layer 3 禁止输出:
- 邮件业务类型、Booking Type、Rooming List 任务或任务卡;
- 后续业务动作、部门、Rate Code、PMS/Opera 参数;
- 客人姓名、同行关系、证件、名单行、名单人数或其他名单明细。
History 只保留完整正文。History 附件不读取、不识别、不进入附件结果。
3. 文件名规则
仅 current_material=true 且文件名完整匹配下式的附件进入 Rooming List 材料检查:
(?i)^LLT(?=[A-Z0-9]*[A-Z])(?=[A-Z0-9]*[0-9])[A-Z0-9]+\.xlsx$
规则含义:
- 去掉
.xlsx后必须以LLT开头; LLT后只允许 ASCII 英文字母与数字,且至少各有一个;- 匹配大小写不敏感,输出 Tour Code 统一大写;
- 不 trim;空格、横线、括号、路径、版本前后缀、
.xls/.xlsm均不接受; - 完整匹配具有附件分流优先权,不再把该附件交给 QBD/LianTai 更新表 Parser。
未命中规则的普通 QBD/LianTai 工作簿只保留原有材料观察,不生成 Rooming List observation/resolution。
4. 安全结构检查
固定上限:原文件 <= 2 MiB、ZIP 条目 <= 256、结构解压读取 <= 16 MiB、Sheet <= 4。业务单元格扫描
固定为 0 行、0 列。
识别器只能流式读取 OOXML 包级结构:Content Types、关系、workbook.xml 的 Sheet 状态,以及 worksheet XML
中的公式元素。不得打开或读取 sharedStrings.xml,不得读取普通单元格值。
以下任一条件使材料保持未解析:
- bytes 不可用、声明大小/哈希不一致、文件超限;
- 不是合法非宏
.xlsxOOXML 包、损坏、加密或受保护; - 包含宏、外部链接、隐藏/veryHidden Sheet、公式;
- Sheet、ZIP 条目或结构解压量超限。
5. 中立结果与原因码
成功时 Layer 3 追加 POSSIBLE_GUEST_LIST_SPREADSHEET observation 与 BOUND target binding;Layer 4 生成
RoomingListResolutionV2(current_excel=true, rooming_list_label=true, target_status=RESOLVED)。
文件名命中但结构检查失败时,仍保留附件、Tour Code 候选、Evidence 与唯一的文件名 binding,新增材料级
parse_issue,Layer 3 从 READY/NOT_APPLICABLE 降为 PARTIAL。Layer 4 输出
tour_code=null / target_status=UNRESOLVED,不得把候选提升为已解析 Tour Code。
稳定原因码按检查顺序选择第一个阻断原因:
ROOMING_LIST_FILENAME_TOUR_CODE_EXACTROOMING_LIST_XLSX_BYTES_UNAVAILABLEROOMING_LIST_XLSX_TOO_LARGEROOMING_LIST_XLSX_SIZE_MISMATCHROOMING_LIST_XLSX_HASH_MISMATCHROOMING_LIST_XLSX_INVALID_PACKAGEROOMING_LIST_XLSX_ENCRYPTED_OR_PROTECTEDROOMING_LIST_XLSX_MACRO_PRESENTROOMING_LIST_XLSX_EXTERNAL_LINK_PRESENTROOMING_LIST_XLSX_TOO_MANY_SHEETSROOMING_LIST_XLSX_HIDDEN_SHEET_PRESENTROOMING_LIST_XLSX_FORMULA_PRESENTROOMING_LIST_XLSX_STRUCTURE_LIMIT_EXCEEDED
同一 Tour Code 的多份附件保持多份中立 resolution。是否形成 Rooming List 候选或
ROOMING_LIST_MULTIPLE_FILES_FOR_TARGET Risk 仍由 Layer 5 决定。
6. 数据流与兼容
Current attachments
→ deterministic filename + OOXML metadata recognizer
→ recognition snapshot in existing MaterialPackage attributes
→ QBD/LianTai Parser receives only non-Rooming workbook view
→ Parsing Agent handles existing Parser/body materials only
→ local Layer 3 merge
→ deterministic Rooming Layer 3 enrichment
→ Layer 4 typed rooming_list_resolutions[]
→ Layer 5 Booking Agent business decision
- 复用现有
MaterialPackageartifact 与 attributes 扩展点,不改 DTO shape、不新增 DDL。 - 复用现有 contracts-v2 类型与 JSON Schema,不升级契约版本。
- Parser v1、Parsing Agent v1 Skill/schema/Main Prompt/package、独立
rooming-list-xlsx-parser均不修改。 - feature 关闭/旧 artifact 不含识别属性时,Rooming 结果保持空,兼容现有 replay。
7. 非目标
- 不读取或统计名单内容,不调用
rooming-list-xlsx-parser。 - 不修改前端,不创建 V2→V4 authoritative writer 或最终 TaskCard。
- 不调用真实 Parsing/Booking Provider、AgentBus WebSocket、数据库、PMS/Opera/OHIP。
- 不开始 CP5 平台绑定,不删除 CP6
parseLegacy、旧 Recovery 或历史 migration。
8. 验收矩阵
- 文件名正反矩阵、大小写与 Tour Code 规范化;
- 2 MiB/4 Sheet/256 entry/16 MiB 边界;伪 XLSX、哈希/大小不一致、加密、宏、外链、隐藏 Sheet、公式;
- 合成姓名哨兵不得出现在 Layer 3、MaterialPackage、DecisionInput、Agent wire 或日志;
- 更新表单独、更新表+Rooming、仅Rooming body-only、多更新表 fail-closed;
- History 同名附件不进入结果;Parsing Agent request 不含 Rooming 附件;
- direct worker 重启/Agent失败后结果稳定;enrichment 重放幂等;
- Layer 4 resolved/unresolved 与 Layer 5 单附件/重复附件/伪造引用本地防线;
- QBD 114/4、LianTai 70/6 和既有 focused/full suite 不回退。
9. 实现归属
CurrentRoomingListAttachmentRecognizer:完整文件名、附件身份与 OOXML 包级安全结构检查;不提取业务单元格。RoomingListMaterialSnapshotCodec:在既有MaterialPackage.current_materials[].attributes中集中编码/解码识别快照。RoomingListLayer3Enricher:在 Parser/Agent 本地合并结果之后幂等追加 observation、binding 与材料级 issue。RoomingListResolverV2:在 canonical input hash 计算前生成现有rooming_list_resolutions[]。BookingContractAssembler:让公共 Parser、FAILED fallback 和兼容parseLegacy只看到排除 Rooming 候选后的当前附件视图。FixedChannelParsingAgentDownstreamCompletion:从持久化MATERIAL_PACKAGE恢复全部当前附件及 Evidence,再应用同一 Layer 3 enrichment。BookingDecisionInputFactoryV2:生成 per-attachment observations、typed resolutions,并校验 Evidence closure。BookingAgentCandidateDecoderV2/BookingDecisionValidatorV2Impl:拒绝 attachment、Tour Code、Evidence 不一致或同 Tour Code 多份有效附件的成功 Rooming target。
上述实现未改变 BookingContractsV2、JSON Schema、Parser v1、Parsing Agent v1 Skill/Main Prompt/package、
Layer4ContextAssemblerV2、DDL 或独立 rooming-list-xlsx-parser。
10. 本地验收结果
- main compile:通过。
- Rooming 识别、Parser 分流、Layer 3/4、Layer 5/6、CP4 direct completion、隐私与边界 focused: 62 tests,0 failures/errors。
- 边界用例覆盖精确文件名、2 MiB、4 Sheet、256 ZIP entries、16 MiB 结构读取、伪装/OLE、大小与哈希不一致、 保护、宏、外链、隐藏 Sheet、公式、History 排除、body-only、多普通工作簿 fail-closed、重复附件和伪造引用。
- 合成姓名哨兵未进入 MaterialPackage、Layer 3、DecisionInput 或 Parsing Agent request;Agent request 也不包含 Rooming 附件文件名、bytes 或内容。
- 最终全量 Maven 快照为 919 tests、1 failure、0 errors、9 skipped。唯一失败是既有
ReservationV4CommandControllerTest.shouldResolveRoomInformationReviewWhenDisplayPayloadAlreadyUsesStableModel的 expected 200 / actual 400,不经过本识别路径。为保护并行成果,本任务未越界改写该V4行为,因此不宣称 整仓全绿。 - 当前仓库没有批准的 QBD/LianTai 真实样本文件/hash,无法在本轮重跑 114/4 与 70/6;这两个数字仍以既有 canonical acceptance evidence 为基线,本轮不伪称已复验。
- 验收期间未连接真实 Provider、AgentBus WebSocket、数据库、PMS、Opera 或 OHIP,未启动 CP5/CP6。