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

167 lines
9.1 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.
# 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 材料检查:
```text
(?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. 数据流与兼容
```text
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。