From a3505f3921c5af37dd01d3bffba70bfa6db198f6 Mon Sep 17 00:00:00 2001 From: andy Date: Wed, 16 Sep 2026 17:11:16 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=BC=E5=85=A5=E8=A1=A8=E5=A4=B4=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...20260916-roster-optional-phone-01a0858b.md | 38 +++++++ agent设计规范/business-adaptation-registry.md | 2 +- agent设计规范/skills/lwlt-lifecycle/SKILL.md | 2 +- .../lwlt-lifecycle/references/input-contract.md | 4 +- .../templates/business-input-templates.md | 4 +- .../test-fixtures/lwlt-lifecycle/release-gate.md | 4 +- .../roster-optional-phone-01a0858b/README.md | 31 ++++++ .../roster-optional-phone-01a0858b/README.md | 3 + .../lwlt-arrangement-0.5.127.skill | Bin .../lwlt-confirmation-0.5.127.skill | Bin .../lwlt-lifecycle-0.5.127.skill | Bin .../lwlt-newbooking-0.5.127.skill | Bin .../lwlt-updating-0.5.127.skill | Bin .../release-manifest.json | 69 +++++++++++++ .../老挝联泰AI指令表-0.5.134.docx | Bin control-plane/README.md | 2 +- control-plane/src/business-routes.ts | 2 +- .../src/passenger-roster-workbook.ts | 31 +++--- .../test/passenger-roster-workbook.test.ts | 96 ++++++++++++++++++ dist/lwlt-arrangement-0.5.128.skill | Bin 0 -> 5965 bytes dist/lwlt-confirmation-0.5.128.skill | Bin 0 -> 4070 bytes dist/lwlt-lifecycle-0.5.128.skill | Bin 0 -> 8269 bytes dist/lwlt-newbooking-0.5.128.skill | Bin 0 -> 5961 bytes dist/lwlt-updating-0.5.128.skill | Bin 0 -> 6027 bytes dist/release-manifest.json | 34 +++---- dist/老挝联泰AI指令表-0.5.135.docx | Bin 0 -> 34390 bytes mappings/lifecycle.mapping.json | 2 +- tools/repository-hygiene.test.mjs | 2 +- 28 files changed, 281 insertions(+), 45 deletions(-) create mode 100644 .project-docs/30-worklog/tasks/20260916-roster-optional-phone-01a0858b.md create mode 100644 archive/evidence/2026-09-16/roster-optional-phone-01a0858b/README.md create mode 100644 archive/releases/2026-09-16/roster-optional-phone-01a0858b/README.md rename {dist => archive/releases/2026-09-16/roster-optional-phone-01a0858b}/lwlt-arrangement-0.5.127.skill (100%) rename {dist => archive/releases/2026-09-16/roster-optional-phone-01a0858b}/lwlt-confirmation-0.5.127.skill (100%) rename {dist => archive/releases/2026-09-16/roster-optional-phone-01a0858b}/lwlt-lifecycle-0.5.127.skill (100%) rename {dist => archive/releases/2026-09-16/roster-optional-phone-01a0858b}/lwlt-newbooking-0.5.127.skill (100%) rename {dist => archive/releases/2026-09-16/roster-optional-phone-01a0858b}/lwlt-updating-0.5.127.skill (100%) create mode 100644 archive/releases/2026-09-16/roster-optional-phone-01a0858b/release-manifest.json rename {dist => archive/releases/2026-09-16/roster-optional-phone-01a0858b}/老挝联泰AI指令表-0.5.134.docx (100%) create mode 100644 dist/lwlt-arrangement-0.5.128.skill create mode 100644 dist/lwlt-confirmation-0.5.128.skill create mode 100644 dist/lwlt-lifecycle-0.5.128.skill create mode 100644 dist/lwlt-newbooking-0.5.128.skill create mode 100644 dist/lwlt-updating-0.5.128.skill create mode 100644 dist/老挝联泰AI指令表-0.5.135.docx diff --git a/.project-docs/30-worklog/tasks/20260916-roster-optional-phone-01a0858b.md b/.project-docs/30-worklog/tasks/20260916-roster-optional-phone-01a0858b.md new file mode 100644 index 0000000..18ec0e1 --- /dev/null +++ b/.project-docs/30-worklog/tasks/20260916-roster-optional-phone-01a0858b.md @@ -0,0 +1,38 @@ +# 名单附件兼容缺少电话列 + +## 范围与授权 + +- 用户授权:兼容修复已提供的 XLSX 名单因缺少“电话”表头而被拒绝的问题。 +- 仅修改名单附件标准化和相关测试、当前业务契约;缺少电话列时输出空电话,已有电话列的内容继续保留。 +- 不修改原始客户附件,不将真实旅客资料保存为测试夹具,不执行 ERP 写入、部署或重启。 + +## Worktree 检查 + +- Branch: `main` +- Worktree: `/Users/andy/IdeaProjects/LWLT-AIBOT` +- Base commit: `8a0f02c9be4141feb9aecfdeb0051ea6c0748bf3` +- Existing changes: 未跟踪 `.idea/`,与本任务无关,保留原样。 +- Other worktrees: 无。 +- Overlap: Clear。使用当前工作区;Feature 模式只写本任务的项目记忆记录。 + +## 已知证据 + +- 原附件 11269 字节,SHA-256 `a109854555d0cc9343fa7e416cf469418cde6748c4baf4fb3bd6627a89a4de3c`,与用户生产日志一致。 +- 当前 v1.6.0 复现 `roster_workbook_header_not_found`;第 2 行缺少电话表头。 +- 仅在内存增加空电话列后,原附件 8 行通过标准化。未改动原文件。 + +## 结果与验证 + +- 已完成:名单标准化器升级为 `ltjt-passenger-roster-workbook-v1.7.0`。电话表头改为可选;缺列输出空电话,存在时照常读取、检查重复表头及非法值。其他 11 个业务字段仍必需,输出仍为 canonical 13 列。 +- 不从无表头的数字推断电话;原表无表头的数字不导入。明确标记为“领队”的记录仍受姓名和电话必填规则约束。 +- 增加缺列、删列、重排列名、合并备注、XLS 转换路径及旧电话校验回归。真实原附件只在内存读取:8 行、8 个空电话,Program Parser 返回 `agent_parse_passed`,原始 SHA-256 未变。 +- 同步名单输入契约、生命周期 mapping、业务入口和操作说明。输入契约及 DOCX 为 `0.5.135`;五个 Skill 统一发布为 `0.5.128`,旧发布物按原哈希归档。插件保持 `0.5.186`,没有数据库迁移。 +- 验证:定向名单测试 35/35;`check:repo` 10/10;`check` 通过;`test:control-plane` 271/271;`test:legacy` 417/417;`build` 通过;`git diff --check` 通过。 +- 五个 Skill 官方校验和 ZIP/源码逐文件比较通过;当前发布清单、源文件哈希及旧发布物哈希通过。DOCX 渲染后逐页检查全部 16 页,中文正常、无裁切;第 5 页为新名单说明。 +- 完整仓库检查在临时干净源码快照运行,保留工作区既有 `.idea/`、`.DS_Store` 和旧忽略日志,不删除或收编。快照中的 2742 个源/文档/发布文件与工作区逐文件哈希一致。首次卫生检查仅因本次 DOCX 预览目录尚未清理失败;清理本次预览目录后 `check:repo` 和 `test:legacy` 全部通过。 +- 主线程最终只读复核:PASS;未启用多 Agent。无真实 ERP 写入、部署、服务重启、提交或推送。生效需用户更新并重启服务端。 +- 脱敏验证结论:[证据说明](../../../archive/evidence/2026-09-16/roster-optional-phone-01a0858b/README.md)。 + +## Promotion Candidates + +- 后续 Integration 可将“名单原文件电话列可选;缺列留空;领队电话仍必填;不推断无表头数字”同步到 canonical 项目记忆。本次 Feature 未修改 canonical 项目记忆。 diff --git a/agent设计规范/business-adaptation-registry.md b/agent设计规范/business-adaptation-registry.md index 0e7ae43..67e5176 100644 --- a/agent设计规范/business-adaptation-registry.md +++ b/agent设计规范/business-adaptation-registry.md @@ -20,7 +20,7 @@ | `team_order_create` | 独立团单个下单 | [`lwlt-newbooking`](skills/lwlt-newbooking/SKILL.md) / `team_order_create` | [业务入口](businesses/team_order_create.md) | [ERP 流程](businesses/team_order_create.md) | [Skill actions](skills/lwlt-newbooking/references/actions-and-fields.md) | 已真实验证 | | `shared_plan_create` | 散拼团新增计划 | [`lwlt-newbooking`](skills/lwlt-newbooking/SKILL.md) / `shared_plan_create` | [业务入口](businesses/shared_plan_create.md) | [ERP 流程](businesses/shared_plan_create.md) | [Skill actions](skills/lwlt-newbooking/references/actions-and-fields.md) | 单个/批量母团已重复验证;E2E3/E2E4 均证明批量每日期具体子单、客户与 15+1,统一发布仍待批准 | | `shared_child_order_create` | 散拼团单个新增子单/计划 | [`lwlt-newbooking`](skills/lwlt-newbooking/SKILL.md) / `shared_child_order_create` | [业务入口](businesses/shared_child_order_create.md) | [ERP 流程](businesses/shared_child_order_create.md) | [Skill actions](skills/lwlt-newbooking/references/actions-and-fields.md) | 已重复真实创建并完成后续全生命周期;仍受统一发布门槛约束 | -| `passenger_list_import` | 独立团/散拼子单名单导入/补充 | [`lwlt-lifecycle`](skills/lwlt-lifecycle/SKILL.md) / `passenger_list_import`(Program-only) | [统一输入模板 §6—7](templates/business-input-templates.md);文字定位 + 单个 `.xls/.xlsx` 附件;程序在前 100 行自动定位唯一 ERP 字段表头,按精确语义从任意表头行和列顺序中只选择必需字段,并读取其下连续名单数据;身份证、年龄、源证件类型和其他普通额外列忽略且不输出 | 识别 route 后等待附件 → 程序规范化为加密 13 列 TSV,并从唯一严格`领队`备注行提取姓名/电话 → 读取 ERP 游客位 → 未确认的占用序号要求覆盖确认;确认后所有指定序号强制覆写(同值也写)→ `DaoRuDones` → 原生游客位不足时返回“名单 N 人超过 ERP 最多 M 人”且不保存 → 恢复未指定行 → 投影领队联系人 → 完整写前投影 → 父页原生保存;ERP 明确返回成功即完成,不再逐行写后回查 | 用户模板 `.xls` 已只读通过 25 行规范化及单一领队行结构核验;解析阶段不以初始 16/31 行作统一静态上限,5000 为技术上限;执行时以精确 ERP 页面实际物化游客位为准。2026-08-28 一笔散拼子单 25 行及领队联系人已持久化全等;另一次独立团 25 人只物化 16 位并在保存前安全阻断 | 名单与领队联系人真实写入已有一笔证据;`0.5.155` 起确认覆盖同值也写,`0.5.156` 起容量不足使用人数/上限业务提示并仅在技术详情保留原始 blocker;其他对象/边界继续按发布门槛分级 | +| `passenger_list_import` | 独立团/散拼子单名单导入/补充 | [`lwlt-lifecycle`](skills/lwlt-lifecycle/SKILL.md) / `passenger_list_import`(Program-only) | [统一输入模板 §6—7](templates/business-input-templates.md);文字定位 + 单个 `.xls/.xlsx` 附件;程序在前 100 行自动定位唯一 ERP 字段表头,按精确语义从任意表头行和列顺序中选择 11 个必需字段及可选电话列(缺少时输出空值,存在时仍须唯一并校验),并读取其下连续名单数据;身份证、年龄、源证件类型和其他普通额外列忽略且不输出 | 识别 route 后等待附件 → 程序规范化为加密 13 列 TSV,并从唯一严格`领队`备注行提取姓名/电话 → 读取 ERP 游客位 → 未确认的占用序号要求覆盖确认;确认后所有指定序号强制覆写(同值也写)→ `DaoRuDones` → 原生游客位不足时返回“名单 N 人超过 ERP 最多 M 人”且不保存 → 恢复未指定行 → 投影领队联系人 → 完整写前投影 → 父页原生保存;ERP 明确返回成功即完成,不再逐行写后回查 | 用户模板 `.xls` 已只读通过 25 行规范化及单一领队行结构核验;解析阶段不以初始 16/31 行作统一静态上限,5000 为技术上限;执行时以精确 ERP 页面实际物化游客位为准。2026-08-28 一笔散拼子单 25 行及领队联系人已持久化全等;另一次独立团 25 人只物化 16 位并在保存前安全阻断 | 名单与领队联系人真实写入已有一笔证据;`0.5.155` 起确认覆盖同值也写,`0.5.156` 起容量不足使用人数/上限业务提示并仅在技术详情保留原始 blocker;其他对象/边界继续按发布门槛分级 | | `order_update_shared_plan` / `order_update_shared_child` | 散拼母团容量/散拼子单住宿说明 | [`lwlt-updating`](skills/lwlt-updating/SKILL.md) | [统一输入模板:修改](templates/business-input-templates.md) | `DoInfoSP` / `DoInfo_order`;写前读取当前值 | 母团容量、子单住宿说明通过;用户只填目标值;无年份定位日期取任务日后的下一次发生日 | Skill 全量解析;仅已验证字段自动执行,其他字段保留并转人工复核 | | `order_update_independent` | 独立团信息修改 | [`lwlt-updating`](skills/lwlt-updating/SKILL.md) / `order_update_independent` | [统一输入模板 §15](templates/business-input-templates.md) | `DoInfoJH`;写前读取当前值;SGL/TWN 分别映射 `frenshu0`/`frenshu1`,成人/占床儿童/不占床儿童/领队分别映射 `darenshu`/`xiaorenshu`/`ertrenshu`/`quanrenshu` | 标间数 `8→9→8` 已有明确响应和 fresh GET;无年份定位/目标日期取下一次发生日;SGL/TWN 与四类人数待新版本授权 ERP 实写复测 | Skill 全量解析;当前插件执行标间数、SGL/TWN 与四类人数,其他目标保留并转人工复核 | | `arrangement_guide` / `arrangement_vehicle` / `arrangement_hotel` / `arrangement_transport` / `arrangement_other` | 安排导游/用车/酒店/大交通/其他备案 | [`lwlt-arrangement`](skills/lwlt-arrangement/SKILL.md) | [统一输入模板 §8—12](templates/business-input-templates.md) | 五类 action-specific `DoInfo_*`,全类 `create|clear`;酒店另有窄 `update`,程序模式支持五类创建指令加“变更”;用车新增/变更支持选填用车类型,与结算单位搜索共同筛选唯一候选;大交通新增/变更支持选填车票说明,与结算单位共同筛选唯一候选;原日期仅定位已有安排,支持 MM-DD 由指定团队中唯一原记录确定年份,YYYY-MM-DD 精确匹配,歧义列候选并停止;导游按团队唯一已有导游定位 | 两类团队共 10 create + 10 clear;酒店资源/房型由唯一 ERP 模糊匹配结果带入;大交通省略车票说明时及其他/备案的结算单位组合候选按下拉顺序首条原生联动,其他/备案数量可选,省略时保留 ERP 默认值;散拼母团无子单时 ERP 禁止安排酒店并隐藏提交入口,插件在三项页面证据同时成立时提示先新增子单 | create/clear 与酒店窄 update 已有真实证据;程序模式五类资源替换变更已完成本地回归,待真实 ERP 验收;状态和直接修改联动字段继续阻断 | diff --git a/agent设计规范/skills/lwlt-lifecycle/SKILL.md b/agent设计规范/skills/lwlt-lifecycle/SKILL.md index 21f3d7c..c75895a 100644 --- a/agent设计规范/skills/lwlt-lifecycle/SKILL.md +++ b/agent设计规范/skills/lwlt-lifecycle/SKILL.md @@ -11,7 +11,7 @@ description: 定义 LTJT 的独立团或散拼子单名单导入、按序号补 1. 从首行和正文识别名单导入、取消或恢复。 2. 按 [input-contract.md](references/input-contract.md) 检查用户可见必填字段。 -3. 名单 route 先进入 `awaiting_attachment`;只接收一份 `.xls`/`.xlsx`。控制面程序在前 100 行中自动定位唯一的 ERP 名单字段表头,按精确字段语义从任意列顺序中选择 12 个必需源字段,再把表头下方的连续名单数据生成内部 13 列 canonical TSV。性别、出生日期采用受支持的身份证模板公式时,程序仅为验证公式读取同一行身份证并校验缓存结果;身份证不进入输出。年龄、源证件类型和其他普通额外列仍忽略。附件到齐前不启动解析或执行。具体公式范围见 `references/input-contract.md`。 +3. 名单 route 先进入 `awaiting_attachment`;只接收一份 `.xls`/`.xlsx`。控制面程序在前 100 行中自动定位唯一的 ERP 名单字段表头,按精确字段语义从任意列顺序中选择 11 个必需源字段和可选的电话列;缺少电话列时电话输出为空,有电话列时按原规则读取和校验,再把表头下方的连续名单数据生成内部 13 列 canonical TSV。性别、出生日期采用受支持的身份证模板公式时,程序仅为验证公式读取同一行身份证并校验缓存结果;身份证不进入输出。年龄、源证件类型和其他普通额外列仍忽略。附件到齐前不启动解析或执行。具体公式范围见 `references/input-contract.md`。 4. Program Parser 校验内部 13 列表头、每行完整性、正整数唯一序号;允许用户只提供本次需要补录的一个或多个序号。备注去空格后严格等于`领队`的唯一行会生成结构化 `passenger_list.leader_contact`;姓名或电话为空、或出现多行领队时失败关闭。 5. 按 [operation-contract.md](references/operation-contract.md) 生成一个 operation。 6. 返回 `agent_parse_passed`、`agent_parse_needs_input` 或 `agent_parse_blocked`。 diff --git a/agent设计规范/skills/lwlt-lifecycle/references/input-contract.md b/agent设计规范/skills/lwlt-lifecycle/references/input-contract.md index 9e47c99..a0d3f37 100644 --- a/agent设计规范/skills/lwlt-lifecycle/references/input-contract.md +++ b/agent设计规范/skills/lwlt-lifecycle/references/input-contract.md @@ -60,7 +60,7 @@ 示例同时附一份符合 ERP 字段规则的名单工作簿。 -附件必须且只能有一个可见工作表。程序在前 100 行中自动定位唯一表头;表头可直接位于第一行,也可位于团信息或说明行之后,列顺序任意,表头下一行起的名单数据必须连续。表头必须各包含一次这些 ERP 语义字段:`序号/姓名/英文姓名(或 NAME)/性别/出生日期/出生地/护照号码(或证件号码)/签发地/签发日期(或签发日)/有效期/电话/备注`。程序选择和校验这些必需字段;`年龄`、源`证件类型`以及其他普通额外列均被忽略。`身份证号码(或身份证)`仅在性别或出生日期使用下述固定公式时作为校验来源,其余情况下忽略;身份证原值不会进入 ERP 或内部 canonical TSV。程序把英文姓名映射为 `NAME`、护照号码映射为“证件号码”、固定输出“证件类型=护照”,并把签发日期映射为“签发日”。 +附件必须且只能有一个可见工作表。程序在前 100 行中自动定位唯一表头;表头可直接位于第一行,也可位于团信息或说明行之后,列顺序任意,表头下一行起的名单数据必须连续。表头必须各包含一次这些 ERP 语义字段:`序号/姓名/英文姓名(或 NAME)/性别/出生日期/出生地/护照号码(或证件号码)/签发地/签发日期(或签发日)/有效期/备注`。电话列可选:缺少时在内部 13 列 TSV 中输出空电话,不从无表头数字或其他列推断;存在时只能有一列,继续读取和校验其内容。程序选择和校验上述必需字段及存在的电话列;`年龄`、源`证件类型`以及其他普通额外列均被忽略。`身份证号码(或身份证)`仅在性别或出生日期使用下述固定公式时作为校验来源,其余情况下忽略;身份证原值不会进入 ERP 或内部 canonical TSV。程序把英文姓名映射为 `NAME`、护照号码映射为“证件号码”、固定输出“证件类型=护照”,并把签发日期映射为“签发日”。 顶部团信息或说明区的 Excel 错误值(如 `#VALUE!`)不作为表头标签;名单字段中的错误值仍阻断。性别、出生日期兼容以下固定身份证推算公式(示例 `E3` 必须对应唯一身份证列的同一行;列重排后按实际位置匹配): @@ -73,7 +73,7 @@ 若某位游客是领队,该行`备注`去除首尾空格后必须严格等于`领队`,并同时填写该行`姓名`和`电话`。一份名单最多标记一位领队;标记成功后程序会把这两个值写入 ERP `联系人/领队人`和`电话`,该行仍作为普通游客导入。`领队备注`等其他文字不触发写入;没有严格标记时保留 ERP 原联系人信息。正文里的`领队`字段仍只是订单定位的选填补充关键词,不是联系人写入来源。 -只接收一个 `.xls`/`.xlsx` 文件;旧版 `.xls` 必须经隔离转换得到真实 XLSX,不能回退原始字节。多工作表、隐藏的必需名单字段数据、宏、外部链接、必需字段中的非模板公式、必需字段断行、空名单、非正整数/重复序号均失败关闭。普通额外列可以有值、公式或被隐藏,但外部公式、超链接及其他主动内容仍按全工作簿安全边界阻断。最多 5000 行且最高序号 5000。附件错误不得把单元格值、文件正文或明文文件名写入日志或 API 错误。 +只接收一个 `.xls`/`.xlsx` 文件;旧版 `.xls` 必须经隔离转换得到真实 XLSX,不能回退原始字节。多工作表、隐藏的已选名单字段数据、宏、外部链接、已选字段中的非模板公式、必需字段断行、空名单、非正整数/重复序号均失败关闭。普通额外列可以有值、公式或被隐藏,但外部公式、超链接及其他主动内容仍按全工作簿安全边界阻断。最多 5000 行且最高序号 5000。附件错误不得把单元格值、文件正文或明文文件名写入日志或 API 错误。 用户可提供一个或多个游客序号。规范化后的每个内部数据行必须完整包含 13 列;未提供的序号不代表删除或清空。ERP 独立团默认 16 行、散拼子单默认 31 行只是初始行基线,不是导入上限;执行端按现有行数与最高序号动态扩行。 diff --git a/agent设计规范/templates/business-input-templates.md b/agent设计规范/templates/business-input-templates.md index 7163462..7c26dd3 100644 --- a/agent设计规范/templates/business-input-templates.md +++ b/agent设计规范/templates/business-input-templates.md @@ -1,6 +1,6 @@ # 运营业务 AI 输入模板总表 -交付版本:0.5.134 +交付版本:0.5.135 适用范围:当前 23 条业务路由,按 19 项运营场景分组;执行能力以生命周期发布门槛为准。 本文件用于向系统提交 ERP 业务需求。复制对应模板填写;示例只供参考,不要直接用于生产业务。 @@ -154,7 +154,7 @@ 名单只通过一份 `.xls` 或 `.xlsx` 附件提交,不再粘贴到文字输入框。系统识别名单业务后会等待附件,附件到齐后只走程序解析。 -系统会在工作表前 100 行中自动定位唯一的名单表头;表头可以直接在第一行,也可以位于团信息或说明行之后,字段顺序任意,表头下一行开始识别连续名单数据。表头必须各包含一次这些 ERP 语义字段:`序号/姓名/英文姓名(或 NAME)/性别/出生日期/出生地/护照号码(或证件号码)/签发地/签发日期(或签发日)/有效期/电话/备注`。系统读取和校验这些必需字段;`年龄`、源`证件类型`以及其他普通额外列会被忽略,不进入 ERP。每次只保留一个可见工作表,最多 5000 行;宏、外部链接等主动内容仍会被安全阻断。 +系统会在工作表前 100 行中自动定位唯一的名单表头;表头可以直接在第一行,也可以位于团信息或说明行之后,字段顺序任意,表头下一行开始识别连续名单数据。表头必须各包含一次这些 ERP 语义字段:`序号/姓名/英文姓名(或 NAME)/性别/出生日期/出生地/护照号码(或证件号码)/签发地/签发日期(或签发日)/有效期/备注`。电话列可以省略,省略时电话留空;如需导入电话号码,请保留一列“电话”表头,系统不会把无表头数字猜作电话。系统读取和校验这些必需字段及存在的电话列;`年龄`、源`证件类型`以及其他普通额外列会被忽略,不进入 ERP。每次只保留一个可见工作表,最多 5000 行;宏、外部链接等主动内容仍会被安全阻断。 名单模板中按同一行身份证自动推算性别和出生日期的固定公式可以保留。请保留唯一的`身份证号码`或`身份证`列,18 位号码使用文本格式保存;系统会核对公式计算结果,身份证本身不导入 ERP。公式结果缺失、错误或与身份证不一致时,需要先在表格中修正。直接填写性别和出生日期时,身份证列仍被忽略。顶部说明区的错误值不影响识别;旅客资料中的错误值需要修正。 diff --git a/agent设计规范/test-fixtures/lwlt-lifecycle/release-gate.md b/agent设计规范/test-fixtures/lwlt-lifecycle/release-gate.md index 13c0aac..8744eb2 100644 --- a/agent设计规范/test-fixtures/lwlt-lifecycle/release-gate.md +++ b/agent设计规范/test-fixtures/lwlt-lifecycle/release-gate.md @@ -6,7 +6,7 @@ - `0.5.186` 修复车票说明中车次与时刻的数字边界,明确供应商与说明联合唯一匹配及多候选提示;新增/变更本地合成回归通过,真实 ERP 验收待部署方完成。见[任务记录](../../../.project-docs/30-worklog/tasks/20260916-transport-description-match-01a0858b.md)。 - Agent Prompt:`ltjt-agent-prompt-v1.8-independent-headcount-categories` - 生命周期契约:`ltjt-lifecycle-v2.9-roster-leader-contact-2026-08` -- 五个 Skill:`0.5.127`;运营 DOCX:`0.5.134` +- 五个 Skill:`0.5.128`;运营 DOCX:`0.5.135` - 发布状态:核心窄能力已有真实证据;一笔名单附件 Program-only 任务已把 25 行及唯一领队联系人正确保存到 ERP,后续只读逐字段核验全等。两种写后逐行读取方式都曾在真实成功写入后产生假阴性;名单在全部写前门禁通过后,以父表单 ERP 明确成功响应作为终结证据,不再执行写后逐行回查或自动名单对账。`0.5.155` 规定确认覆盖的指定序号同值也写;`0.5.156` 把原生游客位不足统一映射为包含名单人数和 ERP 实际上限的业务提示,原技术 blocker 仅留技术详情。`0.5.157` 新增散拼母团“整团游客信息”的 `shared_plan + visitor-list + tid-only` 窄分支,静态契约与回归已通过,仍待授权后的新版运行态只读复测。`0.5.158` 把正式控制面 `https://lwlt.nianxx.cn` 同步加入 Popup、后台、Manifest 权限和 content script 精确白名单;其他 HTTPS origin 仍保持阻断。`0.5.159` 修复 MV3 后台恢复被中断后持久化 `running` 永久阻断插件派发的问题:仅在内存恢复 Promise 已不存在时收敛为 `interrupted`,真实活动恢复仍保持阻断,下一次成功只读保活把状态归零为 `idle`。`0.5.160` 为独立团单个下单写前漂移增加仅字段名诊断,并把数字后缀动态应收字段纳入保护。`0.5.161` 等待客户、跟单人和销售人原生 lookup 数据就绪后才开始单团预检;生产反馈证明仅检查 lookup 数据仍不足。`0.5.162` 进一步要求页面 jQuery Ajax 在预检前归零,并在 `GetProduct` 后等待原生 `ajaxStop` 再应用最终业务字段。`0.5.163` 按生产操作方明确要求恢复 `0.5.156` 的实际校验范围:核心订单字段继续写前阻断,带编号的动态 `ys_*` 应收行不再纳入保护哈希,允许 ERP 原生回调在预检后调整这些字段。`0.5.164` 新增平台账号、AgentBus 渠道、唯一云电脑 worker 与 ERP 登录身份四方一致门禁;旧未绑定渠道和历史未归属 AgentBus 任务默认不执行。`0.5.165` 让散拼新增计划和独立团批量下单在本地候选未命中时先使用表单原生非空产品检索,实测两类表单均能由完整关键词唯一返回目标产品;本轮未勾选或保存,自动选择与写入仍由原门禁保护。新增独立团房型/人数映射仍待实写;未验证宽能力继续失败关闭。 - `0.5.166` 在散拼母团列表入口加入立即检查、100ms 条件轮询和 15 秒总超时;每次探测都重新取得当前主 iframe document,按钮一旦可用便立即继续。该等待只发生在点击前,不固定拖慢快速页面,也不触发业务写入重试。 @@ -16,7 +16,7 @@ - `0.5.172` 按维护方要求将酒店新增 `DoInfo_jiudian` 的固定字段门槛从 195 调整为 150,恢复原来的预检流程;`0.5.171` 的结构判定方案已撤回并归档。其他模式/业务原门槛及后续执行检查保留,低于 150 的页面仍会阻断。尚未部署或进行真实 ERP 写入验收;验证范围见[任务记录](../../../.project-docs/30-worklog/tasks/20260909-hotel-form-readiness-01a0858b.md)。 - `0.5.173` 修复名单 TSV 末尾空列被整体 `trim()` 删除的问题,覆盖服务端统一 operation 校验、插件派发及原生名单合并。13 列完整性、序号、覆盖确认及领队约束继续执行;服务端与插件需同步更新,数据库无需变更。该版本的本地验证与真实 ERP 验收边界见[任务记录](../../../.project-docs/30-worklog/tasks/20260910-roster-trailing-empty-columns-01a0858b.md)。 - 运营输入/DOCX `0.5.127` 补齐第 19 项`散拼团多个新增子单`的可复制模板与示例;该入口仍固定为 Program-only,不进入 Agent Prompt 或 Skill。 -- 名单工作簿 normalizer `v1.6.0` 继续选择 12 个必需源字段;新增固定身份证推算性别/生日公式的同一行来源和缓存一致性校验,顶部说明区错误值不作为表头。身份证只用于该公式校验,不进入 canonical 输出;其余普通额外列仍忽略。必需字段错误、宏/外链、全局超链接和外部公式等安全门槛保持失败关闭。验证范围见[验证记录](../../../archive/evidence/2026-09-15/roster-template-formulas-01a0858b/README.md),未执行真实 ERP 导入。 +- 名单工作簿 normalizer `v1.7.0` 选择 11 个必需源字段及可选电话列;电话列缺少时输出空值,不推断无表头数字,存在时仍须唯一并接受原有校验;标记领队仍须有姓名和电话。保留固定身份证推算性别/生日公式的同一行来源与缓存一致性校验,顶部说明区错误值不作为表头。身份证仅用于公式校验,其余普通额外列仍忽略。已选字段错误、宏/外链、全局超链接和外部公式等安全门槛保持失败关闭。缺少电话列的验证见[当前任务](../../../.project-docs/30-worklog/tasks/20260916-roster-optional-phone-01a0858b.md),此前公式验证见[验证记录](../../../archive/evidence/2026-09-15/roster-template-formulas-01a0858b/README.md);未执行真实 ERP 导入。 运行中的浏览器版本必须实时握手确认。当前制品文件名和 SHA-256 只看 [`../../../dist/release-manifest.json`](../../../dist/release-manifest.json),不从历史日志推断。 diff --git a/archive/evidence/2026-09-16/roster-optional-phone-01a0858b/README.md b/archive/evidence/2026-09-16/roster-optional-phone-01a0858b/README.md new file mode 100644 index 0000000..ea1c845 --- /dev/null +++ b/archive/evidence/2026-09-16/roster-optional-phone-01a0858b/README.md @@ -0,0 +1,31 @@ +# 名单缺少电话列兼容验证 + +日期:2026-09-16。此文件保存本次验证的历史结论,不作为当前业务规则或运行输入。未保存真实名单、旅客资料、生产日志或秘密配置。 + +## 行为与真实附件 + +- 标准化器:`ltjt-passenger-roster-workbook-v1.7.0`。 +- 原始 XLSX:11269 字节,SHA-256 `a109854555d0cc9343fa7e416cf469418cde6748c4baf4fb3bd6627a89a4de3c`;处理前后哈希一致。 +- 第 2 行识别出 11 个必需业务字段,电话表头缺失;成功标准化 8 行,电话均为空,canonical TSV 仍为 13 列。 +- Program Parser 返回 `agent_parse_passed`。验证仅在内存执行,未创建任务或提交 ERP。 +- 无表头数字不作为电话;有电话表头时保留原有校验;领队仍要求姓名和电话。 + +## 验证结果 + +| 检查 | 结果 | +| --- | --- | +| 名单定向测试 | 35/35 | +| `node --run check:repo` | 10/10 | +| `node --run check` | PASS | +| `node --run test:control-plane` | 271/271 | +| `node --run test:legacy` | 417/417 | +| `node --run build` | PASS | +| 五个 Skill 官方校验 | PASS | +| 五个 Skill ZIP 与源码逐文件核对 | PASS | +| 当前发布清单、源码及构建器 SHA-256 | PASS | +| 旧版本归档 SHA-256 | PASS | +| DOCX 全部 16 页 PNG 目视检查 | PASS | + +仓库检查在临时干净源码快照执行,避开工作区原有 IDE、系统文件及忽略日志;未清理这些原有文件。快照与工作区 2742 个文件逐文件哈希一致。本次预览输出清理后重新运行卫生及 legacy 检查通过。 + +交付版本为 Skill `0.5.128`、操作 DOCX/输入契约 `0.5.135`;插件仍为 `0.5.186`。当前发布物以 `dist/release-manifest.json` 为准。本次未部署、未重启服务、未操作 ERP。 diff --git a/archive/releases/2026-09-16/roster-optional-phone-01a0858b/README.md b/archive/releases/2026-09-16/roster-optional-phone-01a0858b/README.md new file mode 100644 index 0000000..4c47b1f --- /dev/null +++ b/archive/releases/2026-09-16/roster-optional-phone-01a0858b/README.md @@ -0,0 +1,3 @@ +# 旧名单输入契约发布物 + +只读历史,不能作为当前业务规则。此目录按原 SHA-256 保留五个 0.5.127 Skill、0.5.134 操作 DOCX 和更新前发布清单;当前交付物以根目录 dist/release-manifest.json 为准。 diff --git a/dist/lwlt-arrangement-0.5.127.skill b/archive/releases/2026-09-16/roster-optional-phone-01a0858b/lwlt-arrangement-0.5.127.skill similarity index 100% rename from dist/lwlt-arrangement-0.5.127.skill rename to archive/releases/2026-09-16/roster-optional-phone-01a0858b/lwlt-arrangement-0.5.127.skill diff --git a/dist/lwlt-confirmation-0.5.127.skill b/archive/releases/2026-09-16/roster-optional-phone-01a0858b/lwlt-confirmation-0.5.127.skill similarity index 100% rename from dist/lwlt-confirmation-0.5.127.skill rename to archive/releases/2026-09-16/roster-optional-phone-01a0858b/lwlt-confirmation-0.5.127.skill diff --git a/dist/lwlt-lifecycle-0.5.127.skill b/archive/releases/2026-09-16/roster-optional-phone-01a0858b/lwlt-lifecycle-0.5.127.skill similarity index 100% rename from dist/lwlt-lifecycle-0.5.127.skill rename to archive/releases/2026-09-16/roster-optional-phone-01a0858b/lwlt-lifecycle-0.5.127.skill diff --git a/dist/lwlt-newbooking-0.5.127.skill b/archive/releases/2026-09-16/roster-optional-phone-01a0858b/lwlt-newbooking-0.5.127.skill similarity index 100% rename from dist/lwlt-newbooking-0.5.127.skill rename to archive/releases/2026-09-16/roster-optional-phone-01a0858b/lwlt-newbooking-0.5.127.skill diff --git a/dist/lwlt-updating-0.5.127.skill b/archive/releases/2026-09-16/roster-optional-phone-01a0858b/lwlt-updating-0.5.127.skill similarity index 100% rename from dist/lwlt-updating-0.5.127.skill rename to archive/releases/2026-09-16/roster-optional-phone-01a0858b/lwlt-updating-0.5.127.skill diff --git a/archive/releases/2026-09-16/roster-optional-phone-01a0858b/release-manifest.json b/archive/releases/2026-09-16/roster-optional-phone-01a0858b/release-manifest.json new file mode 100644 index 0000000..4b6afc2 --- /dev/null +++ b/archive/releases/2026-09-16/roster-optional-phone-01a0858b/release-manifest.json @@ -0,0 +1,69 @@ +{ + "manifest_version": 1, + "generated_on": "2026-09-16", + "baselines": { + "chrome_extension": "0.5.186", + "skills": "0.5.127", + "business_instruction_docx": "0.5.134", + "agent_prompt": "ltjt-agent-prompt-v1.8-independent-headcount-categories" + }, + "artifacts": [ + { + "kind": "chrome_extension", + "version": "0.5.186", + "path": "dist/ltjt-order-assistant-0.5.186.zip", + "source": "chrome-extension/ltjt-order-assistant", + "sha256": "c79d108ce4cbed85a856b336e1643fd990d81f21d16a0bbd66be27510d1c2568" + }, + { + "kind": "skill", + "name": "lwlt-arrangement", + "version": "0.5.127", + "path": "dist/lwlt-arrangement-0.5.127.skill", + "source": "agent设计规范/skills/lwlt-arrangement", + "sha256": "ae3fc66965d2a7968aeaa2ecf371d75e5365ef4cc4dfd8ef080f9343e0d0f09c" + }, + { + "kind": "skill", + "name": "lwlt-confirmation", + "version": "0.5.127", + "path": "dist/lwlt-confirmation-0.5.127.skill", + "source": "agent设计规范/skills/lwlt-confirmation", + "sha256": "c2f3689d8a0b4d6b250bb2cfce572fe3a9fca3f5519ea5fae5ef0d382b44dae4" + }, + { + "kind": "skill", + "name": "lwlt-lifecycle", + "version": "0.5.127", + "path": "dist/lwlt-lifecycle-0.5.127.skill", + "source": "agent设计规范/skills/lwlt-lifecycle", + "sha256": "f0b5cdea11e65657fb9b10e4f7d020769d5477cc8ceddfcfd6a284513345f6bc" + }, + { + "kind": "skill", + "name": "lwlt-newbooking", + "version": "0.5.127", + "path": "dist/lwlt-newbooking-0.5.127.skill", + "source": "agent设计规范/skills/lwlt-newbooking", + "sha256": "b64593d88145966cd4e702d2532ffe3ea85052e8d56fbe75d503a19ababa1715" + }, + { + "kind": "skill", + "name": "lwlt-updating", + "version": "0.5.127", + "path": "dist/lwlt-updating-0.5.127.skill", + "source": "agent设计规范/skills/lwlt-updating", + "sha256": "54f10dd6bd6d2ddf47c700f1bca4b1fcd3346dc6143bf27118a23587b1b11736" + }, + { + "kind": "business_instruction_docx", + "version": "0.5.134", + "path": "dist/老挝联泰AI指令表-0.5.134.docx", + "source": "agent设计规范/templates/business-input-templates.md", + "builder": "tools/build_business_instruction_docx.py", + "sha256": "b6c1f677b93cb4f7356cfb26c6af01860587be1288ffe9e8aff8295929074490", + "source_sha256": "7446e4560e2eaaf6f490c8ed7523d6aadcee6f94f58cb620f7e71db674404471", + "builder_sha256": "c162884210da22e3b78368749b66f1f177df5e9fc6155f4fd9954bd516d187f1" + } + ] +} diff --git a/dist/老挝联泰AI指令表-0.5.134.docx b/archive/releases/2026-09-16/roster-optional-phone-01a0858b/老挝联泰AI指令表-0.5.134.docx similarity index 100% rename from dist/老挝联泰AI指令表-0.5.134.docx rename to archive/releases/2026-09-16/roster-optional-phone-01a0858b/老挝联泰AI指令表-0.5.134.docx diff --git a/control-plane/README.md b/control-plane/README.md index 6e91e16..abceef2 100644 --- a/control-plane/README.md +++ b/control-plane/README.md @@ -10,7 +10,7 @@ - 业务页面通过 REST 创建任务;Agent 返回结构化结果后,任务归属人在自己的任务上一次点击“确认并提交到 ERP 插件”,再通过 SSE 或轮询读取服务端状态。普通用户与组长的任务 API、SSE、附件和插件执行权限只覆盖分配给本人的人工任务与 AgentBus 任务;管理员是纯管理面身份,不能创建、查看、修改、领取、接收事件或提交任何业务任务。 - 手工与 AgentBus 的每个新任务都会按同一组织、同一 19 项业务路由固化解析策略及配置 revision;来源不能覆盖模式。其中两项名单 route 与散拼批量子单 route 固定为 `program_only`,其余 16 项可配置 `ai / shadow / auto / program`。全消息中的唯一已登记指令可以确定 route;没有指令时,只有全部标签都属于唯一 route、至少两个不同标签且业务定位必填项完整的字段签名才可确定 route。未知、冲突或多 route 输入不猜测。后续补充轮次沿用原任务快照,设置变化只影响新任务和新会话。 - 组长和普通用户使用逐账号白名单,新账号默认没有任何可执行任务类型;管理员自身的任务白名单固定为空,只能在 `/accounts` 为员工逐项授权。已登记但未授权的业务返回 `business_not_authorized`;无法唯一确认 route 的员工输入返回 `business_type_unresolved`。两种拒绝都发生在解析器和 ERP 插件之前,并记录不含明文的授权拒绝审计。权限在补充输入、人工确认、全自动确认和插件领取前再次校验;取消授权后的任务不会进入 ERP 队列。AgentBus 入站使用渠道绑定员工的同一白名单,管理员账号不得成为员工渠道归属人。 -- 名单 route 创建后先进入 `awaiting_attachment`,只接收一份 `.xls/.xlsx`;控制面在前 100 行中自动定位唯一的 ERP 名单字段表头,按精确字段语义从任意表头行和列顺序中只选择 12 个必需源字段,并把表头下方连续名单数据在内存中规范化为 13 列 canonical TSV。身份证、年龄、源证件类型和其他普通额外列不参与名单行识别、字段校验或输出;必需字段缺失/重复、多个候选表头、必需字段中的非法公式及宏、外链等主动内容仍失败关闭。原始工作簿不入库,文件名和 canonical TSV 使用字段加密,解析通过或终止后清除 canonical 中间文本。附件到齐前不会领取解析任务,也不会进入 ERP。独立团初始 16 行、散拼子单初始 31 行仅为 ERP 动态扩行基线,5000 为技术上限。 +- 名单 route 创建后先进入 `awaiting_attachment`,只接收一份 `.xls/.xlsx`;控制面在前 100 行中自动定位唯一的 ERP 名单字段表头,按精确字段语义从任意表头行和列顺序中选择 11 个必需源字段及可选的电话列(缺少时输出空值,不推断无表头数字;存在时仍须唯一并接受原有校验),并把表头下方连续名单数据在内存中规范化为 13 列 canonical TSV。身份证、年龄、源证件类型和其他普通额外列不参与名单行识别、字段校验或输出;必需字段缺失/重复、多个候选表头、已选字段中的非法公式及宏、外链等主动内容仍失败关闭。原始工作簿不入库,文件名和 canonical TSV 使用字段加密,解析通过或终止后清除 canonical 中间文本。附件到齐前不会领取解析任务,也不会进入 ERP。独立团初始 16 行、散拼子单初始 31 行仅为 ERP 动态扩行基线,5000 为技术上限。 - 平台的任务 ID、Agent 会话 ID、确认状态、重要摘要、事件和用户通讯内容只存在于平台任务/会话/结果信封中,不回写到 Agent `operation`,也不成为 ERP 业务字段。 - Agent `operation` 只保存解析态业务事实。插件领取已确认任务后先做无需 ERP 查询的前门禁,再在 ERP 内只读唯一解析对象、资源和当前状态,最后对内部 execution operation 执行严格写前门禁。 - Chrome 插件仍在当前平台账号已登录的浏览器/ERP 会话中工作;每个员工平台账号必须配置唯一 ERP 账号,同一平台账号在 90 秒新鲜期内只允许一台云电脑保持执行 worker。心跳携带扩展对期望 ERP 账号的只读匹配结果;账号不匹配、心跳过期、第二台并发云电脑或任务归属不一致都会在领取和回执两端失败关闭。`chrome.storage.local` 只是临时缓存。 diff --git a/control-plane/src/business-routes.ts b/control-plane/src/business-routes.ts index 18b2d87..9e15aef 100644 --- a/control-plane/src/business-routes.ts +++ b/control-plane/src/business-routes.ts @@ -80,7 +80,7 @@ export function effectiveParserModeForRoute(route: BusinessRouteDefinition, conf } const PROGRAM_VERSION = 'ltjt-program-parser-v1.0.12'; -export const BUSINESS_INPUT_CONTRACT_VERSION = 'business-input-templates-0.5.134'; +export const BUSINESS_INPUT_CONTRACT_VERSION = 'business-input-templates-0.5.135'; const lookupFields = ({ customerRequired = true } = {}): ProgramFieldDefinition[] => [ { key: 'order_no', label: '单号', aliases: ['团号', '订单号'], kind: 'text' }, diff --git a/control-plane/src/passenger-roster-workbook.ts b/control-plane/src/passenger-roster-workbook.ts index 658351d..1203b89 100644 --- a/control-plane/src/passenger-roster-workbook.ts +++ b/control-plane/src/passenger-roster-workbook.ts @@ -13,22 +13,23 @@ const ABSOLUTE_MAX_DATA_ROWS = 5_000; const MAX_PASSENGER_SEQUENCE = 5_000; const MAX_HEADER_ROW = 100; -export const PASSENGER_ROSTER_WORKBOOK_VERSION = 'ltjt-passenger-roster-workbook-v1.6.0'; +export const PASSENGER_ROSTER_WORKBOOK_VERSION = 'ltjt-passenger-roster-workbook-v1.7.0'; const REQUIRED_SOURCE_FIELDS = [ '序号', '姓名', '英文姓名', '性别', '出生日期', '出生地', '护照号码', - '签发地', '签发日期', '有效期', '电话', '备注' + '签发地', '签发日期', '有效期', '备注' ] as const; type RequiredSourceField = typeof REQUIRED_SOURCE_FIELDS[number]; -type SourceColumnMap = Record; +type SourceField = RequiredSourceField | '电话'; +type SourceColumnMap = Record & { 电话?: number }; /** * Header recognition is intentionally exact and finite. It accepts the * required customer-facing labels, canonical ERP labels, and approved aliases. * Non-import columns are deliberately absent from this map and are ignored. */ -const HEADER_FIELD_ENTRIES: ReadonlyArray = [ +const HEADER_FIELD_ENTRIES: ReadonlyArray = [ ['序号', '序号'], ['姓名', '姓名'], ['英文姓名', '英文姓名'], @@ -48,7 +49,7 @@ const HEADER_FIELD_ENTRIES: ReadonlyArray(HEADER_FIELD_ENTRIES); +const SOURCE_FIELD_BY_HEADER = new Map(HEADER_FIELD_ENTRIES); export const CANONICAL_PASSENGER_HEADERS = [ '序号', '姓名', 'NAME', '性别', '出生日期', '出生地', '证件类型', '证件号码', @@ -402,7 +403,7 @@ function rowHasData(row: ExcelJS.Row, sourceColumns: readonly number[]): boolean // These two legacy template formulas derive gender/birth date from a deleted // identity-card column. Recognize the exact broken templates, not arbitrary // formulas or their cached results, when deciding whether a tail row is unused. -const BROKEN_TEMPLATE_FORMULAS: Partial> = { +const BROKEN_TEMPLATE_FORMULAS: Partial> = { 性别: 'IF(OR(LEN(#REF!)=15,LEN(#REF!)=18),IF(MOD(MID(#REF!,15,3)*1,2),"男","女"),NA())', 出生日期: 'DATE(MID(#REF!,7,VLOOKUP(LEN(#REF!),{15,2;18,4},2,0)),MID(#REF!,VLOOKUP(LEN(#REF!),{15,9;18,11},2,0),2),MID(#REF!,VLOOKUP(LEN(#REF!),{15,11;18,13},2,0),2))' }; @@ -434,11 +435,11 @@ function unusedTemplateRow(row: ExcelJS.Row, headerRow: number, sourceColumns: S if (sequenceCell.type === ExcelJS.ValueType.Formula) return false; const sequence = normalizedText(scalarValue(sequenceCell)); if (sequence && (!/^[1-9]\d*$/.test(sequence) || Number(sequence) > MAX_PASSENGER_SEQUENCE)) return false; - for (const field of REQUIRED_SOURCE_FIELDS) { + for (const [field, column] of Object.entries(sourceColumns)) { if (field === '序号') continue; - const cell = row.getCell(sourceColumns[field]); + const cell = row.getCell(column); if (cell.type === ExcelJS.ValueType.Formula) { - const template = BROKEN_TEMPLATE_FORMULAS[field]; + const template = BROKEN_TEMPLATE_FORMULAS[field as SourceField]; if (!formulaAllowed(cell, headerRow, sourceColumns, identityColumn) && (!template || normalizedFormula(cell.formula) !== normalizedFormula(template))) return false; } else if (normalizedText(scalarValue(cell)) !== '') { @@ -516,7 +517,7 @@ function validateFormulasAndHiddenData( } function headerColumnsForRow(sheet: ExcelJS.Worksheet, rowNumber: number): SourceColumnMap | null { - const columns = new Map(); + const columns = new Map(); const row = sheet.getRow(rowNumber); for (let columnNumber = 1; columnNumber <= sheet.columnCount; columnNumber += 1) { const cell = row.getCell(columnNumber); @@ -530,11 +531,9 @@ function headerColumnsForRow(sheet: ExcelJS.Worksheet, rowNumber: number): Sourc } if (!REQUIRED_SOURCE_FIELDS.every((field) => columns.has(field))) return null; - const result: Partial = {}; - for (const field of REQUIRED_SOURCE_FIELDS) { - result[field] = columns.get(field); - } - return result as SourceColumnMap; + // Keep absent optional fields out of the map: all downstream row/formula + // checks operate on actual selected columns, never a guessed neighbour. + return Object.fromEntries(columns) as SourceColumnMap; } function findHeaderLayout(sheet: ExcelJS.Worksheet): { row: number; columns: SourceColumnMap } { @@ -739,7 +738,7 @@ function canonicalRow( canonicalTextCell(cell('签发地')), canonicalDate(issueDateCell, date1904, issueDateCell.type === ExcelJS.ValueType.Formula), canonicalDate(expiryCell, date1904, expiryCell.type === ExcelJS.ValueType.Formula), - canonicalIdentifier(cell('电话')), + sourceColumns['电话'] === undefined ? '' : canonicalIdentifier(row.getCell(sourceColumns['电话'])), canonicalTextCell(cell('备注')) ]; } diff --git a/control-plane/test/passenger-roster-workbook.test.ts b/control-plane/test/passenger-roster-workbook.test.ts index df81e94..3e0b2f9 100644 --- a/control-plane/test/passenger-roster-workbook.test.ts +++ b/control-plane/test/passenger-roster-workbook.test.ts @@ -136,6 +136,102 @@ test('XLSX is deterministically normalized to the canonical 13-column TSV', asyn ].join('\n')); }); +test('an absent phone header produces blank phones without guessing unheaded values', async () => { + const baseline = await normalizeSynthetic(await syntheticWorkbook()); + const expected = baseline.canonicalTsv.split('\n').map((line, index) => { + if (index === 0) return line; + const fields = line.split('\t'); + fields[11] = ''; + return fields.join('\t'); + }).join('\n'); + for (const removeColumn of [false, true]) { + const result = await normalizeSynthetic(await syntheticWorkbook(workbook => { + const sheet = workbook.getWorksheet('Sheet1')!; + if (removeColumn) sheet.spliceColumns(13, 1); + else sheet.getCell('M2').value = null; // The original number below remains unheaded. + })); + assert.equal(result.canonicalTsv, expected); + assert.equal(result.rowCount, 2); + const parsed = await parseProgramInput({ + rawText: `导入散拼子单名单\n预订客户:测试客户\n出发日期:2026-09-18\n名单内容:\n${result.canonicalTsv}`, + receivedAt: new Date('2026-09-16T00:00:00Z') + }); + assert.equal(parsed.status, 'agent_parse_passed'); + } +}); + +test('phone-free rosters support reordered alias headers, merged remarks and XLS conversion', async () => { + const workbook = new ExcelJS.Workbook(); + const sheet = workbook.addWorksheet('无电话模板'); + sheet.mergeCells('B1:K1'); + sheet.getCell('B1').value = '脱敏团队信息'; + sheet.addRow(['序号', '姓名', '英文姓名', '护照号码', '性别', '出生日期', '年龄', '出生地点', '签发地', '签发日期', '有效期至', '备注']); + for (let sequence = 1; sequence <= 8; sequence++) { + sheet.addRow([sequence, '测试游客', 'TEST', `P0000000${sequence}`, '女', '1990-01-02', 36, '测试地', '测试地', '2025-01-02', '2035-01-01', '普通备注']); + } + sheet.mergeCells('L3:L10'); + sheet.getCell('M10').value = 13800000000; // Extra unheaded content must not become a phone. + const xlsx = Buffer.from(await workbook.xlsx.writeBuffer()); + const expected = await normalizeSynthetic(xlsx); + assert.equal(expected.rowCount, 8); + for (const row of expected.canonicalTsv.split('\n').slice(1)) { + assert.equal(row.split('\t').length, 13); + assert.deepEqual(row.split('\t').slice(11), ['', '普通备注']); + } + assert.doesNotMatch(expected.canonicalTsv, /13800000000/); + const legacy = await normalizePassengerRosterWorkbook({ + content: Buffer.from([0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1]), + fileName: 'synthetic.xls', contentType: 'application/vnd.ms-excel' + }, { convertLegacyXls: async () => xlsx }); + assert.equal(legacy.canonicalTsv, expected.canonicalTsv); +}); + +test('phone is the only optional semantic and duplicate phone headers stay blocked', async () => { + for (const column of [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 14]) { + const content = await syntheticWorkbook(workbook => { + const sheet = workbook.getWorksheet('Sheet1')!; + sheet.getCell('M2').value = null; + sheet.getCell(2, column).value = null; + }); + await expectRosterError(() => normalizeSynthetic(content), 'roster_workbook_header_not_found'); + } + await expectRosterError(() => syntheticWorkbook(workbook => { + workbook.getWorksheet('Sheet1')!.getCell('O2').value = '电话'; + }).then(normalizeSynthetic), 'roster_workbook_header_not_found'); +}); + +test('present phone columns retain formula, value, hidden-data and row checks', async () => { + for (const [value, code] of [ + [{ formula: '1+1', result: 2 }, 'roster_workbook_formula_not_allowed'], + [{ error: '#VALUE!' }, 'roster_workbook_invalid_cell'], + [1.5, 'roster_workbook_invalid_identifier'] + ] as const) { + await expectRosterError(() => syntheticWorkbook(workbook => { + workbook.getWorksheet('Sheet1')!.getCell('M3').value = value; + }).then(normalizeSynthetic), code, { row: 3, column: 13 }); + } + await expectRosterError(() => syntheticWorkbook(workbook => { + workbook.getWorksheet('Sheet1')!.getColumn(13).hidden = true; + }).then(normalizeSynthetic), 'roster_workbook_hidden_data'); + await expectRosterError(() => syntheticWorkbook(workbook => { + workbook.getWorksheet('Sheet1')!.getCell('M5').value = '13800000000'; + }).then(normalizeSynthetic), 'roster_workbook_invalid_sequence', { row: 5, column: 1 }); +}); + +test('a marked leader still requires a phone when the source phone column is absent', async () => { + const result = await normalizeSynthetic(await syntheticWorkbook(workbook => { + const sheet = workbook.getWorksheet('Sheet1')!; + sheet.getCell('M2').value = null; + sheet.getCell('N3').value = '领队'; + })); + const parsed = await parseProgramInput({ + rawText: `导入散拼子单名单\n预订客户:测试客户\n出发日期:2026-09-18\n名单内容:\n${result.canonicalTsv}`, + receivedAt: new Date('2026-09-16T00:00:00Z') + }); + assert.notEqual(parsed.status, 'agent_parse_passed'); + assert.match(JSON.stringify(parsed), /姓名和电话都必须填写/); +}); + test('a merged title error is skipped, while header and passenger errors stay blocked', async () => { const baseline = await normalizeSynthetic(await syntheticWorkbook()); const titleError = await normalizeSynthetic(await syntheticWorkbook(workbook => { diff --git a/dist/lwlt-arrangement-0.5.128.skill b/dist/lwlt-arrangement-0.5.128.skill new file mode 100644 index 0000000000000000000000000000000000000000..dea23f8ad7512b1d04e3b3133238f4ce93f5d391 GIT binary patch literal 5965 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 JAnAW@{{;_973=^2 literal 0 HcmV?d00001 diff --git a/dist/lwlt-confirmation-0.5.128.skill b/dist/lwlt-confirmation-0.5.128.skill new file mode 100644 index 0000000000000000000000000000000000000000..63898bff889c2ebbd13431fc70d924bee0f163bc GIT binary patch literal 4070 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 a(|?pYin1`D{y{+hy(oV}Zd&4hUjGX{Mz2r+ literal 0 HcmV?d00001 diff --git a/dist/lwlt-newbooking-0.5.128.skill b/dist/lwlt-newbooking-0.5.128.skill new file mode 100644 index 0000000000000000000000000000000000000000..3b9aa9e170837671a4eeee706ebb65b167bb926a GIT binary patch literal 5961 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 literal 0 HcmV?d00001 diff --git a/dist/lwlt-updating-0.5.128.skill b/dist/lwlt-updating-0.5.128.skill new file mode 100644 index 0000000000000000000000000000000000000000..812cd458dc9265d7792a6a8fad294950e62203e5 GIT binary patch literal 6027 zcmaKwWl$VU)2?xcgvANA1b0|$vET_3+#v}PoMq7s79{u*+}&+~0Kwhe-GaLX3vOTD zbL!N0p6AF+O-;>I-CbS%=jyxFlu*%#k&uwEkO;zAKa}l=o`ql_A!*_M=LZQ%Q%ONt znG5pytBw+sQkQt;f?a;F01`lb4U~)isU)O6rStxaHaa;ID<97+56b|7-35k>DNjVl zi;Bun2#rd}$kapP=h5`!_-E;{WKorhSQskk%Wv_>6R%y-Is3XL6s|Tm)l=~c)~oTH zzI-=SRR|65UP4P4To>mT(Vs5y+H^AS+l%$gZ?z4ba8C|#(_@Y}TiPzdC!7(n&ta!* zx%sNqoBZAy%$z!Vhh(-d%Y5*-tpkHZ^t6LZJQ&dLq0=8@x6h*tg>2Y8N-)YOmC|wr zLSE2a$HX6${*)p4O7-6RaSzOyq$Kp5aaDKc4pcowf%Ztz7tZ_CLBW3 zD@=I^gN7d1<~T>??ER2B#+~I|9?~|%^=CfGCmHrG_=nmU|8w;GK+#QJDFb42vTaT= zuZN{_^7@eo@&)^|KdjSs6N)1NJr-ugaf`TBWr&(z5|)KZcQ*m%wl+}T%;}YA^E71x z2b(T|+7IjP#-vfAd~7By%lR&D^OY>scjUE;Lz9L6SUW`@<4jyJJ741r!wwV7zqdqM zg;$RV3caT5?Cog$I6@~`+R!(<=^=^{YF3jttr9FIi$+Vd6CIs>Vu_ZZfaBwi8V2n7 zoqz&Aa$*O0kFBouZxE@IqT2Hc-}lTx(QC;pL|q94C2W@|F;n4Pv1`#!#^4*Y-##L@ z2LvwFmAL67$e+%L&T^LLR7;Xx+7(VvaNk`zB?2iY48=3@*Z7M$F)Zstvowu+A_R^6 zl!?##D%wI*>1NdWv;a$yAQVgZnu|CID%@;>5mW8~A44vZ=<$;wK}Zhs9?!Z|Rp{km z@Xps5&knI3c8qQ0YQf8}R-NH_JD4A4|2>*M54AvfLc9R42~}5+TJYt5QQIQAP?jW4 zha7h39ni?{qOMn69;yl5cT}V_EuXj!K22D$?{W)gJg>%YOZl}S|7VyluBpE72n!i? z`}n?iIIYN|$s*1G>!pNkAT@s=1~6H`{pI>JW57-ia}395V+KpkFlWrrqF^4(5}4sX zswDm)_{q?vU$N=v17TONY_O-FnessK0f+DwT-_<@MmPRz=TBNWjSu+62BrdE6 zNDKS13tCNPjAtC6t@;$CX5 zkE7p25~m?{PjA(VPLc@Ni2S+tWdL_)vzdW2>s$l{Km(|@m}E0_PdwHWpmQB6x9MU! zDz~~#Y84BLYhcct=nC=1mmk97QfiwF(n+80Xy0&`kP-kbVGa5IY^U(o(z;hL#kB| z=IS=~ZQT7AaLmo`r@q4r;T^fL$A(w7$osu~m`g@_rtz>#%Obc)(T}-^b_s5iVp)x*jcvtvdu1aNhcIIPB?=v=HNC_uftB^^=CoFKL#Px~f?n5K1 zcEn9ie&{1tys=`dLdY#+!K!w!83)l&RE)H}{}8)|Jhi+65gWEkUN}ZkoEL~pI^!(S zl?RbW^DWkFm*KHjJs7Q)hacH*Pc(OYa!KD*xd19#)j8(#prR{b`e;L4HnNfFC;f5X zO6gHw8lusOQBTQ_y=&Ho%UVq*agCATNm!FdQfG}{wio^F%0A@S?8DA!D1$`h50aI` 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 SMM6URy9xddFDyy_^ZG9w&q|U2 literal 0 HcmV?d00001 diff --git a/dist/release-manifest.json b/dist/release-manifest.json index 4b6afc2..2beca46 100644 --- a/dist/release-manifest.json +++ b/dist/release-manifest.json @@ -3,8 +3,8 @@ "generated_on": "2026-09-16", "baselines": { "chrome_extension": "0.5.186", - "skills": "0.5.127", - "business_instruction_docx": "0.5.134", + "skills": "0.5.128", + "business_instruction_docx": "0.5.135", "agent_prompt": "ltjt-agent-prompt-v1.8-independent-headcount-categories" }, "artifacts": [ @@ -18,51 +18,51 @@ { "kind": "skill", "name": "lwlt-arrangement", - "version": "0.5.127", - "path": "dist/lwlt-arrangement-0.5.127.skill", + "version": "0.5.128", + "path": "dist/lwlt-arrangement-0.5.128.skill", "source": "agent设计规范/skills/lwlt-arrangement", "sha256": "ae3fc66965d2a7968aeaa2ecf371d75e5365ef4cc4dfd8ef080f9343e0d0f09c" }, { "kind": "skill", "name": "lwlt-confirmation", - "version": "0.5.127", - "path": "dist/lwlt-confirmation-0.5.127.skill", + "version": "0.5.128", + "path": "dist/lwlt-confirmation-0.5.128.skill", "source": "agent设计规范/skills/lwlt-confirmation", "sha256": "c2f3689d8a0b4d6b250bb2cfce572fe3a9fca3f5519ea5fae5ef0d382b44dae4" }, { "kind": "skill", "name": "lwlt-lifecycle", - "version": "0.5.127", - "path": "dist/lwlt-lifecycle-0.5.127.skill", + "version": "0.5.128", + "path": "dist/lwlt-lifecycle-0.5.128.skill", "source": "agent设计规范/skills/lwlt-lifecycle", - "sha256": "f0b5cdea11e65657fb9b10e4f7d020769d5477cc8ceddfcfd6a284513345f6bc" + "sha256": "fcf23bb0e12e7026f03dc3670fe35db77c740a9902a7a415e2efa464d4eceb1e" }, { "kind": "skill", "name": "lwlt-newbooking", - "version": "0.5.127", - "path": "dist/lwlt-newbooking-0.5.127.skill", + "version": "0.5.128", + "path": "dist/lwlt-newbooking-0.5.128.skill", "source": "agent设计规范/skills/lwlt-newbooking", "sha256": "b64593d88145966cd4e702d2532ffe3ea85052e8d56fbe75d503a19ababa1715" }, { "kind": "skill", "name": "lwlt-updating", - "version": "0.5.127", - "path": "dist/lwlt-updating-0.5.127.skill", + "version": "0.5.128", + "path": "dist/lwlt-updating-0.5.128.skill", "source": "agent设计规范/skills/lwlt-updating", "sha256": "54f10dd6bd6d2ddf47c700f1bca4b1fcd3346dc6143bf27118a23587b1b11736" }, { "kind": "business_instruction_docx", - "version": "0.5.134", - "path": "dist/老挝联泰AI指令表-0.5.134.docx", + "version": "0.5.135", + "path": "dist/老挝联泰AI指令表-0.5.135.docx", "source": "agent设计规范/templates/business-input-templates.md", "builder": "tools/build_business_instruction_docx.py", - "sha256": "b6c1f677b93cb4f7356cfb26c6af01860587be1288ffe9e8aff8295929074490", - "source_sha256": "7446e4560e2eaaf6f490c8ed7523d6aadcee6f94f58cb620f7e71db674404471", + "sha256": "55dcd03b7ddb43cf3333497faeddc105aff3d57729e06cff200a7e190cc95ea2", + "source_sha256": "a28ecf96a09c9c9dfdeed590ccff44999ecd019abd3f30102c98b6cbb66c5f62", "builder_sha256": "c162884210da22e3b78368749b66f1f177df5e9fc6155f4fd9954bd516d187f1" } ] diff --git a/dist/老挝联泰AI指令表-0.5.135.docx b/dist/老挝联泰AI指令表-0.5.135.docx new file mode 100644 index 0000000000000000000000000000000000000000..6ff7967f1cefe22427feaf9e12df6a52a670f5ee GIT binary patch literal 34390 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

k>gI_A#D(DkB9;_Gyv#|T7XSCS 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