Complete the selective V2 checkpoint with its minimal AgentBus, object-storage, replay persistence, and validated-workbench shared dependency closure.
167 lines
9.1 KiB
Markdown
167 lines
9.1 KiB
Markdown
# 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。
|