Files
th-hotel-simple/docs/project/requirements/M012-layer3-current-rooming-list-filename-material-change-request-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

9.1 KiB
Raw Blame History

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 不可用、声明大小/哈希不一致、文件超限;
  • 不是合法非宏 .xlsx OOXML 包、损坏、加密或受保护;
  • 包含宏、外部链接、隐藏/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。

稳定原因码按检查顺序选择第一个阻断原因:

  1. ROOMING_LIST_FILENAME_TOUR_CODE_EXACT
  2. ROOMING_LIST_XLSX_BYTES_UNAVAILABLE
  3. ROOMING_LIST_XLSX_TOO_LARGE
  4. ROOMING_LIST_XLSX_SIZE_MISMATCH
  5. ROOMING_LIST_XLSX_HASH_MISMATCH
  6. ROOMING_LIST_XLSX_INVALID_PACKAGE
  7. ROOMING_LIST_XLSX_ENCRYPTED_OR_PROTECTED
  8. ROOMING_LIST_XLSX_MACRO_PRESENT
  9. ROOMING_LIST_XLSX_EXTERNAL_LINK_PRESENT
  10. ROOMING_LIST_XLSX_TOO_MANY_SHEETS
  11. ROOMING_LIST_XLSX_HIDDEN_SHEET_PRESENT
  12. ROOMING_LIST_XLSX_FORMULA_PRESENT
  13. ROOMING_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
  • 复用现有 MaterialPackage artifact 与 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。