You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mail-yubao/docx/产品规则-邮件指令识别与拆分.md

154 lines
9.7 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 产品规则:邮件指令识别与拆分(锁定口径)
> **地位**:本页为指令「怎么认、怎么拆、谁可确认」的**产品真源**之一。
> **实现真源**:`src/services/parse/instruction-lexicon.ts`、`split-instructions.ts`、`classify.ts`。
> **约束**:解析链路**禁止**依赖 LLM / Cursor 临场理解;改规则先改本页 + 词表 + 单测。
> **日期**:2026-08-03
---
## 0. 一句话
主题与正文**都重要、要分开用**;一封多轮邮件里**只有最新一轮指令可确认**;标准四类走业务表单,非标准/软词走「客户指令」;同线程后续回复按**新 UID**再拉,不重做旧信。
---
## 1. 信号源(三者并列,来源可区分)
| 信号源 | 用途 | UI 来源标签 |
|--------|------|-------------|
| **主题** | 柜号/提单/ETA/「新增预报」「DO请查收」等;可单独成指令单元 | 来自主题 |
| **正文** | 按时间轮/转发标签拆段;决定「当前可确认」 | 来自当前正文 / 来自历史引用 |
| **附件名** | 补 DO / 贴标清单等;**不能**仅凭正文「DO也同步上传」造空上传 DO | 来自附件名 |
冲突原则:
1. 正文**最新段**已是硬工单(换标/覆盖贴/贴标/拍照/拦截等)→ **压过**主题链路上历史「新增预报」。
2. **同线程主题未变**(仅 Re:/Fw: 前缀变化)时:后续轮次**只认该时段正文**,不得再用首封主题「新增预报」造当前/补缺预报卡;QQ 转发壳剥壳后的主题残片也不算指令。
3. 主题有、正文完全无指令时 → 才可用主题补缺(只读或非当前)。
4. 正文已覆盖同类型 → 主题**不再重复**出一张一样的卡。
5. 正文写「DO 也同步上传」但本封**无真实 DO 附件** → **不出**空的上传 DO 指令。
---
## 2. 标准四类业务 ↔ UI
| UI kind | 典型关键词(见词表) | 确认动作 |
|---------|----------------------|----------|
| `forecast` | 新增预报、请查收新增预报 | 预报表单(人工确认) |
| `forecast` | 柜号+派送单,请查收(首票卡派清单) | 预报表单(只读历史) |
| `transfer` | 新增转仓、转仓(「不转仓」除外) | 详情先展示转仓表单;**确认时**再查 CC 到仓闸门,不可转则自动降级工单 |
| `transfer` 截图 | 正文仅「新增转仓请留意」+ 内嵌 JPG 表格 | 对每张截图 OCR → 解析「地址仓→仓库重定向」;按时间轮与附件顺序一一对应展示 |
| `work_order` | 贴标/换标/覆盖贴/操作指令、拍照、**指令性**拦截、快递单号;mail1 仅柜号+预约码 | 客户留言 SaveForm(人工确认) |
| `do_upload` | DO请查收;或真实 `*DO*.pdf` 等 | 上传 DO(人工确认) |
主流程四类均需人工确认,**不**因主题残留「新增预报」自动再写 CC。
> **渠道件数 ≠ 整票指令**:主题里的 `拦截-209件` / `FedEx-29件` 只是渠道汇总;整票真实指令以「拆柜清单更新 / 派送要求」为准。禁止把渠道名写成备注「邮件动作:拦截」。
---
## 3. 客户指令(非标准 / 软词)
下列**不**硬套工单表单,归 `customer_instruction`(只读展示轮次/正文):
- 更新派送单
- 改自提 / 改为仓库自提 / 仓库自提
- 拆柜清单 / 卡转海 / 派送要求
- 按照正常预报接受、帮忙安排派单、安排派单
- 继续暂存 / 暂存等后续
- 有实质内容但无法归入标准四类的段落
---
## 4. 多轮线程拆分与「仅最新可确认」
### 4.1 如何切开
正文按下列边界切段(保留分隔标签到后一段,便于取时间/发件人):
- `在 yyyy-mm-dd … 写道` / `On … wrote:`
- `原始邮件` / `转发的邮件` / `Original Message` / `Original:`
- 发件人+发送时间 等邮件头块
**不用**单独的 `Dear` 作为切段点(避免同轮内误切)。
### 4.2 可确认范围
| 段 | `isCurrent` | 操作 |
|----|-------------|------|
| 最新一条有实质指令的段 | `true` | 可确认提交 |
| 更早的引用轮次(标准四类) | `false` | 只读(如历史预报) |
| 更早的软词「客户指令」 | `false` | **独立时间轮要出卡**:按正常预报接受 / 仓库「好的」 / 无法接收;仅丢掉无时间轮的「更新派送单」噪声 |
| 纯主题补缺单元 | 一般为 `false` | 只读展示线索 |
同轮内允许多种 UI 并存(例如当前换标 + 历史预报只读)。
`work_order_actions` 仅含「转仓」、或正文已拆出转仓/预报等标准单元时,**不得**再补一张工单卡。
历史引用若正文指令相同(同线程连转同一份「拦截 + 改自提」等,仅抄送折行不同)→ **只保留最新一条**,禁止出 2/3/4 张一样的工单卡。
工单备注须列出本段全部动作:硬词(拦截/贴标)与软词(改自提)并存时都写入「邮件动作」,不得只留拦截。
### 4.3 跳过 vs 仍展示的轮次
- **跳过(不出卡)**:QQ 转发壳、`发自我的iPhone`、空的 `Original:`、主题残片
- **仍按时间轮出卡(只读、不可确认)**:仓库 ACK「好的 / 收到」;「无法接收 / 产能有限」;「按照正常预报接受 / 安排派单」
- **同轮内 `====` 分组**(如换标 334 件两段 FBA)**不切开**,仍是这一轮一条工单
---
## 5. 同线程后续指令(拉取幂等)
| 情况 | 行为 |
|------|------|
| 客户在同主题下**新回复**(新 IMAP UID) | **会拉**:新邮件入库、重新拆段;仅最新段可确认 |
| 已入库的旧 UID | **不再拉**(`knownUids` / messageId / rawHash 幂等) |
| 超出 `IMAP_LOOKBACK_DAYS`(默认 3 天)的过旧回复 | 可能拉不到 |
| 新回复未过过滤规则 | 记拉取日志为跳过,不进业务列表 |
旧邮件保持原状态;**不会**因新回复自动把旧预报/旧工单再执行一遍。
---
## 6. 柜头 / 预报相关(与指令并存)
- **提拆派**:预报时 `F_OperationType=0` 表示提拆派服务包,**不是**三个独立管理端「提柜/拆柜/派送」界面。
- **mail1 类**(仅柜号+预约码、无标准关键词):`classify` → `WORK_ORDER`;详情用 `work_order_actions` 补当前工单单元(见 `extractMailInstructions({ workOrderActions })`)。
- 模板表尾「注意:…」是填写说明,**不是**货件行。
- **预报未映射标签进备注**:主题/正文 `+` 分段里,已有 `名称:值` 前缀但对不上预报 UI 的字段(如 `封号:EMCEJJ0635`)写入 `F_MemoRemark`,**不得**当作客户名与 `YWZD` 一类短码竞争。
- 卡派清单列:附件有则填;UI **隐藏整列皆空**的 FormOrder 列,避免满屏「-」。
- 工单留言内容:取当前指令段,并从 `Dear` / `原箱号` 起,去掉转发头;**禁止**用整封线程正文盖住分段留言。
- **附件 ↔ 指令段(全邮件通用,禁止按单封特判)**:业务附件挂到**本段**表单(工单 `F_AttachFile` / 出库 `F_LabelFile`),按优先级:
1. **主键交叉**:附件名与本段正文/主题抽出同一业务主键则挂本段。主键:`FBA…`、原箱号 `YT…`、FNSKU `X0…`、唛头 `WL…`。**不用 ISO 柜号**分发工单附件(避免历史换标/拦截卡误挂当前文件)。
2. **文件名原文**:正文/主题出现该附件主文件名(去扩展名、去 `(1)` 副本后缀)→ 挂本段。
3. **角色兜底(仅当前可确认段)**:附件名无主键,但含 `卡转海` / `换标|覆盖贴|操作指令|贴标交付`,且本段也有对应角色词 → 挂当前段。历史只读段不用角色兜底。
4. **DO 文件**只进上传 DO 卡,不进工单附件。
5. **卡派资料/装箱清单 xlsx**是预报/转仓解析源,不进工单附件,除非规则 2 正文点名该文件。
6. 跳过 `*邮箱.pdf` / QQ 截图。一封多轮时每段独立匹配,**不得**把整封附件列表复制到每一张卡。
- **贴标指令单 ≠ 卡派预报行**:`lineage.template=label-instruction` 时,货件行只服务工单/出库核对;**新增预报**货件列表必须为空,不得把换标行(仓码当 Address、无体积毛重)当成 SaveContainer 预报展示。预报柜号优先主题/正文,不以贴标单内其它柜号覆盖。
- **同封多表格**:同时有卡派/提拆派 xlsx 与换标指令 xlsx 时,解析**优先卡派预报表**生成 `shipments`;换标文件仍作附件挂工单。
---
## 7. 实现与测试对照表
| 规则 | 代码 | 单测(示例) |
|------|------|----------------|
| 词表 / 软硬分流 | `instruction-lexicon.ts` | `mail4-time-rounds.test.ts` |
| 拆段 / 最新可确认 / 主题补缺 | `split-instructions.ts` | `split-instructions.test.ts`、`mail4-time-rounds` |
| 正文硬工单压过主题预报 | `classify.ts` | `classify.test.ts`、`instruction-product-rules` |
| 线程拆单(Message 级) | `thread.ts` + poller | `thread.test.ts` |
| UID 幂等拉取 | `poller.ts` `knownUids` | 集成/烟雾 |
| 空 DO 不出指令 | `split-instructions` + `do-upload-extract` | `mail4-time-rounds`、`do-upload-extract` |
| 工单留言清洗 | `CcWorkOrderForm` `extractWorkOrderMessageBody` | `four-business.test.ts` |
| 附件↔指令段 | `match-segment-attachments.ts` | `match-segment-attachments.test.ts`、`four-business.test.ts` |
改口径流程:**改本页 → 改词表/拆分 → 改/补单测 → `pnpm test` 相关文件通过**。
---
## 8. 与旧文档关系
- `docx/需求规格-邮件自动预报-v0.2.md` §4 类型打分仍有效;**本页补充**「拆分 / 客户指令 / 主题正文分工 / 仅最新确认」。
- 若与旧表述冲突,**以本页 + 上述实现文件为准**,并回写需求规格对应章节。
- Cursor 对话纪要**不是**运行时真源。