# Ritfit Adcode

> 每天早上9点自动扫描吴双(Christina)飞书邮箱过去24小时收到的邮件，从中提取 KOL adcode 信息 （Post URL + Adcode + 产品），匹配到 Feishu Base 产品库，把完整记录连同 Month/Deliverables/ Posted?/Posting Date 一起写入 Content Log 子表单，并把格式化清单推送到吴双的飞书私信。也支持 吴双随时手动粘贴邮件原文/原始 IG/TikTok 链接触发同样的提取流程，当场在对话里回复。触发词： "adcode"、"今天的adcode"、"扫一下adcode邮件"、"帮我记录这些adcode"、"这是今天的红人链接"、 "extract adcode"、"处理一下这批adcode"，以及 cron job "Daily adcode email scan"。

- Skill: `nana7536/ritfit-adcode` (Agent Skill)
- Install (CLI): `npx skillmds@latest add nana7536/ritfit-adcode`
- Raw SKILL.md: https://api.skillmd.com/api/skills/nana7536/ritfit-adcode/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: nana7536 (https://skillmd.com/u/nana7536)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/nana7536/ritfit-adcode

---


# RITFIT Adcode 邮件扫描 → Base 记录 → 飞书通知

两种触发方式,共用同一套"提取 → 校验 → 产品匹配 → 去重 → 写入"逻辑,只是输入来源和输出方式不同:

1. **Mode 0 — 每日自动扫描邮件**(cron 09:00 BJT,job "Daily adcode email scan"):自动查吴双飞书
   邮箱过去24小时收到的邮件,逐封判断是否含 KOL adcode 信息,提取后走完整流程,最后把这次扫描
   到的所有结果汇总成**一条**消息推送到她的飞书私信。**这是默认/主要工作方式,不需要吴双手动粘
   贴任何东西。**
2. **Mode A — 手动模式**:吴双随时把邮件原文或裸链接直接粘贴进对话,触发同样的提取流程,当场在
   对话里回复结果(不走 `mcp__claw__notify`,因为她本人就在对话里)。用于临时补充处理 Mode 0 没
   覆盖到的邮箱/邮件(比如她自己转发过来的一封邮件)。

---

## Base 配置(已用 `lark-cli base +field-list` 验证,2026-07-17)

### 目标表:Content Log(子表单)
| 项目 | 值 |
|------|-----|
| Base Token | `Dj0BbQHGKaiaFssqeWucIBIen8g` |
| Table ID | `tblP5ZPXXzKXibYU` |
| View | `vewAw5Jshe` |

**本技能常规写以下 7 个字段,其余一律不写、不改**(2026-07-24 新增 Month/Deliverables/Posted?/Posting Date,吴双明确要求扫描adcode时顺手一起填):

| 字段名 | 字段 ID | 类型 | 说明 |
|--------|---------|------|------|
| Adcode | `fldabyan83` | text | 必填 |
| Post URL | `fldqba9rTE` | text(url 样式) | 必填(有例外,见下方"缺 Post URL 的不完整记录也写入 Base"规则) |
| Product | `fldeNkyvNH` | **link** → `tblYFQZrZUIHRtjR` | 选填,匹配不到就留空 + 消息里标注 |
| Month | `fldvKrtDCj` | select(选项:`Jan`/`Feb`/`Mar`/`Apr`/`May`/`Jun`/`Jul`/`Aug`/`Sep`/`Oct`/`Nov`/`Dec`,英文三字母缩写) | **收到这条 adcode 对应邮件的日期**所在的月份(不是扫描时间,是邮件本身的收件日期);Mode A 手动粘贴场景没有邮件收件时间,用吴双粘贴当天的日期。 |
| Deliverables | `fldXx9xrSL` | text | 按平台自动判断:Post URL 是 `instagram.com/...` → 填 `1 reel`;是 `tiktok.com/...`/`vt.tiktok.com/...` → 填 `1 TK`。缺 Post URL 时看正文/上下文里是否明确提到平台(如提到"IG"/"Instagram"/"Reel" 或 "TikTok"/"TK"),能判断就按同样规则填,判断不了就留空(消息里标注 `⚠️平台未判断,Deliverable留空`)。 |
| Posted? | `fldwFfqCvJ` | checkbox | 只要这条记录写入 Base(不管完整记录还是仅 Adcode 的不完整记录),就勾选 `true` —— 收到 adcode 就说明内容已经发布了。 |
| Posting Date | `fldwNfFAKS` | datetime(格式 `yyyy/MM/dd`) | 收到这条 adcode 对应邮件的收件日期(跟 Month 用的是同一个日期来源);Mode A 场景用吴双粘贴当天的日期。 |

**条件写入(仅限"Adcode 有、Post URL 缺"这一种不完整记录,2026-07-22 吴双明确要求新增)**:

| 字段名 | 字段 ID | 类型 | 说明 |
|--------|---------|------|------|
| KOL Name | `fldVYkDzgG` | **link** → `tblBqCCxHRtFvS9E`(ALL KOLs 表) | 默认不写。只有当一条记录因为缺 Post URL 而以"仅有 Adcode"的不完整形式写入 Base 时,才尝试识别网红身份并写入这个字段,方便吴双日后回去核对/补链接。识别不到就不写,消息里文字标注网红名字即可。识别规则见下方"KOL 身份识别"。 |

**只读展示,不写入**:

| 字段名 | 字段 ID | 类型 | 说明 |
|--------|---------|------|------|
| Campaign | `fldeRQOZ8E` | select(World Cup / Independence / Member / BFCM / Pink) | 本技能不写这个字段,但如果记录已有 Campaign 值(比如之前已存在的记录,或吴双/别的流程手动填过),推送消息时要把它带出来展示,见"输出"一节。 |

⚠️ 不要写的字段(表里还有,但和 adcode 提取无关,是别的流程用的):`Pay Rate`、`Payment Date`、`Payment Status`、`KOL Contract`、`Contract Campaign Lookup`、`Payment done?`、`父记录 4`。**`KOL Name` 不在这份"绝对不碰"名单里** —— 它只在上面那一种特定场景(缺 Post URL 的不完整记录)才会被尝试写入,其余场景(完整记录、去重命中的已存在记录等)仍然完全不碰,继续留给别的流程处理。`Month`/`Deliverables`/`Posted?`/`Posting Date` 从 2026-07-24 起改为本技能常规写入字段(见上表),不再属于"不要写"名单。

### 产品匹配表:Product 表(link 目标)
| 项目 | 值 |
|------|-----|
| Table ID | `tblYFQZrZUIHRtjR` |
| 主字段(匹配用) | `Product Name`(`fldqX8WDeZ`,text) |
| 辅助匹配字段 | `Chinese Name`(`flduWQ0bDl`)、`SKU`(`flddvgHEIT`) |

### KOL 匹配表:ALL KOLs 表(link 目标,仅缺 Post URL 场景使用)
| 项目 | 值 |
|------|-----|
| Table ID | `tblBqCCxHRtFvS9E` |
| 匹配用字段 | `KOL Name`(`fldq03deU6`,text) |

---

## File structure(本地状态/日志)

| 路径 | 用途 |
|------|------|
| `F:\Cherry Studio\Andy\Data\_outputs\ritfit-adcode-outputs\last-scan.md` | 记录上次 Mode 0 扫描到的截止时间(ISO8601),下次运行的起点 |
| `F:\Cherry Studio\Andy\Data\_outputs\ritfit-adcode-outputs\daily-log-DD-MM-YYYY.md` | 每次 Mode 0 运行都写一条:扫描窗口、扫了几封邮件、几封候选、最终几条完整/信息不全/已存在跳过/产品未匹配 |

Mode A(手动粘贴)不写这两个文件,只在对话里回复。

---

## Mode 0 — 每日自动扫描邮件

### 邮箱身份
- 用 `lark-cli mail` 系列命令,`--as user --mailbox me`,即吴双本人登录飞书邮箱账号本身,不需要
  额外指定邮箱地址。
- 第一次跑之前(或怀疑身份不对时)用以下命令确认 `me` 确实是吴双本人:
  ```
  lark-cli mail user_mailboxes profile --params '{"user_mailbox_id":"me"}' --as user
  ```

### 扫描时间窗口(状态文件,避免漏扫/重复扫)
1. 读 `last-scan.md` 拿上次记录的 `last_scan_end`;文件不存在或读取失败,就用"当前时间 − 24小时"
   当起点(兜底,保证覆盖"过去24小时"这个需求)。
2. `scan_start = last_scan_end`,`scan_end = 本次运行开始时的当前时间`。
3. 不管这次扫描结果如何(有没有找到 adcode 邮件),运行结束时把 `scan_end` 写回 `last-scan.md`
   作为下次起点 —— 这样即使运行时间有偏差,也不会漏扫或重复扫同一封邮件。

### 拉邮件
```
lark-cli mail +triage --filter '{"folder":"inbox","time_range":{"start_time":"<scan_start>","end_time":"<scan_end>"}}' --mailbox me --as user --max 100 --format json
```
如果返回 `has_more=true`,用返回的 `page_token` 续页(`search:`/`list:` 两种前缀不能混用),把这个
时间窗口内的邮件拉完。

**不加 `--query` 关键词过滤** —— 直接拉这个时间窗口内 inbox 的全部邮件,交给下一步人工判断,避
免因为 KOL 措辞五花八门("adcode"/"ad code"/"add code"/西班牙语"código"等)而用关键词误漏。

### 逐封判断 + 读正文
对每封邮件:
1. 用 `lark-cli mail +message --message-id <id> --html=false --as user --format json` 拿纯文本
   正文(`body_plain_text`)。
2. 判断这封邮件是否疑似"KOL发来的、包含帖子链接或adcode信息"的邮件——明显不相关的(内部通知、
   账单、无关广告、纯感谢但完全没提到任何 code/链接的)直接跳过,不算候选,不进入下面的提取流程。
3. 疑似相关的,进入下一节"提取"(和 Mode A 共用同一套逻辑)。

---

## 提取 / 校验 / 匹配 / 去重 / 写入(Mode 0 和 Mode A 共用)

Mode 0 里"一封邮件正文"和 Mode A 里"吴双粘贴的一段文本"走的是同一套逻辑,下面统一说"输入内容"。

### 第一步:提取

输入内容可能是:
- 一整段邮件原文(可能包含多个 KOL、多条链接、混着中英文/西语说明);
- 直接甩几条裸链接(IG/TikTok),可能附带 adcode 文字,也可能不附带。

对输入内容里能识别出的**每一条 IG/TikTok 链接**,尝试在同一段/同一行/紧邻上下文里找到对应的:
- **Post URL**:匹配 `instagram.com/...`、`tiktok.com/...`、`vt.tiktok.com/...` 等格式的完整链接。
- **Adcode**:通常紧跟在"adcode"、"ad code"、"add code"、"code"、"促销码"、"折扣码"、"优惠码"等
  关键词后面的字母数字组合;也可能就是一段独立的大写/数字混合短字符串。没有明确标签时,按上下文
  最贴近该链接的候选词处理。
- **产品名候选**:文本里出现的产品词(如 "M2"、"Gazelle Pro"、"Gorilla"、"20lb dumbbells" 等),
  不要求精确拼写,后面会做匹配。

一条链接 = 一条待处理记录。如果同一段输入里有多个链接,拆成多条,分别提取三个字段。如果输入里
完全没有链接,但有明显的 adcode 值(如"我发视频提到产品了,给你adcode: XXX"这种只发code没发链接
的情况),仍然按"缺 Post URL"的不完整记录处理,不要因为没有链接就整个跳过不提取。

### 第二步:必填字段校验

**规则(2026-07-22 更新,缺 Post URL 的处理方式已改变)**:

- **Adcode 缺**(不管 Post URL 有没有)→ 这条记录不算候选,不写入 Base,列到"⚠️信息不全"分组,并注明
  缺了什么、原始文本片段是什么(方便吴双回去核对)。
- **Adcode 有、Post URL 也有** → 完整记录,进入第三步产品匹配,正常走完整流程写入。
- **Adcode 有、Post URL 缺** → 不再算"信息不全跳过不写"。改为"仅 Adcode 不完整记录",**同样写入
  Base**(Post URL 字段留空),额外走一次"KOL 身份识别"(见下方),写入后在推送消息里单独标注
  `⚠️缺 Post URL`,提醒吴双回去看/要链接,不再进入"⚠️信息不全"分组(那个分组现在专指"缺 Adcode"
  的记录)。
- **说明到这一步就停,不要额外提议"要不要帮你起草回复邮件问对方要链接"之类的下一步动作**
  (2026-07-17 吴双明确要求)。缺 Post URL 就是缺 Post URL,标注清楚即可,要不要联系 KOL 补链接
  由吴双自己决定。

### KOL 身份识别(仅适用于"Adcode 有、Post URL 缺"的不完整记录)

1. 从这条记录的来源文本里找网红身份:优先用邮件发件人显示名(From 姓名),没有明显发件人信息时用
   邮件签名/正文里提到的人名(如"Terrell and Jarius"这种落款)。
2. 用这个名字去 ALL KOLs 表做模糊搜索:
   ```
   lark-cli base +record-search --base-token Dj0BbQHGKaiaFssqeWucIBIen8g --table-id tblBqCCxHRtFvS9E --search-field "KOL Name" --keyword "<提取到的人名>" --as user
   ```
3. 对返回结果做精确比对(trim 后完全相等才算命中,不能看到有结果就认为匹配上,参考 jdy-kol-sync /
   ritfit-kol-register 同款去重规则)。
   - **匹配成功** → 记下该记录的 `record_id`,写入时 `KOL Name` 字段用 link 格式:
     `{"id": "<record_id>"}`。
   - **匹配失败**(没搜到 / 搜到多条无法判断)→ `KOL Name` 字段留空,不写入这个字段,推送消息里仍
     用文字形式标注识别到的人名,并加 `⚠️网红未匹配 Base 记录`。
4. 如果连"识别到的人名"这一步都做不到(邮件里完全看不出是谁),消息里网红那一行显示
   `⚠️未能识别发件人`,`KOL Name` 字段不写。

### 第三步:产品匹配

1. 查询 Product 表:
   ```
   lark-cli base +record-search --base-token Dj0BbQHGKaiaFssqeWucIBIen8g --table-id tblYFQZrZUIHRtjR --search-field "Product Name" --keyword "<提取到的产品名>" --as user
   ```
   如果没搜到,再用 `Chinese Name` 试一次(有些产品吴双可能用中文提到)。
2. 匹配规则:忽略大小写、忽略空格/连字符差异(如 "GazellePro" ≈ "Gazelle Pro" ≈ "Gazelle-Pro" 都
   算匹配同一个)。只接受能明确对应到**一条**产品记录的匹配;如果搜出多条容易混淆的结果,当作未
   匹配处理,别瞎猜。
3. **匹配成功** → 记下该记录的 `record_id`,写入时用 link 格式:`{"id": "<record_id>"}`。
4. **匹配失败**(没搜到 / 搜到多条无法判断)→ Product 字段留空,不写入这个字段,消息里该条记录
   标注 `⚠️产品未匹配(原文:"<提取到的产品名候选>")`。

### 第四步:去重检查

写入前,先按 Adcode 查一遍 Base,避免同一封邮件被处理两次导致重复记录(这一步对"完整记录"和"仅
Adcode 不完整记录"都适用,只要 Adcode 相同就按同一条处理):
```
lark-cli base +record-search --base-token Dj0BbQHGKaiaFssqeWucIBIen8g --table-id tblP5ZPXXzKXibYU --search-field "Adcode" --keyword "<Adcode>" --as user
```
如果搜到完全相同的 Adcode(且 Post URL 也一致,或者两边都是"仅 Adcode"没有 Post URL),跳过写入,
视为已存在,消息里标注 `↩️已存在,跳过`。

⚠️ 已知限制(暂不自动处理,记录在案供后续决定要不要补):如果一条"仅 Adcode"的不完整记录之前已经
写入 Base,后来同一个 Adcode 又出现在新邮件里且这次带了 Post URL,目前逻辑只会判定"Adcode 已存
在,跳过",不会自动回填 Post URL 补全那条旧记录。如果吴双需要这种"自动补全"能力,需要另外明确
要求再加(类似 jdy-shipping-track 的 B2.5 实时补写逻辑)。

顺手把这条已存在记录当前的 **Campaign**(`fldeRQOZ8E`)字段值记下来 —— 如果 `+record-search`
返回结果里已经带了完整字段就直接读,没带全的话用 `+record-get --record-id <id> --field-id Campaign --as user`
单独查一次。留着给"输出"一节推送用:有值就展示,没值(比如还是空的)就不展示这一行。

新建的记录(没被去重跳过的)因为本技能不写 Campaign,所以肯定是空的,不用查,直接跳过展示。

### 第五步:写入 Base

对每条通过校验(且未被去重跳过)的记录:

**先算好 Month / Deliverables / Posted? / Posting Date 这四个值(2026-07-24 新增)**:
- **收件日期**:取这条记录来源邮件的收件日期(Mode 0 用 `+triage`/`+message` 返回结果里的时间字段,
  不是 `scan_end`;Mode A 手动粘贴场景没有邮件收件时间,用吴双粘贴当下的日期)。
- `Posting Date` = 收件日期,格式 `yyyy/MM/dd`。
- `Month` = 收件日期对应的月份三字母缩写(`Jan`~`Dec`),对应 Base 里 Month 字段的现成选项。
- `Posted?` = 固定 `true`(只要这条记录要写入 Base,不管完整还是仅 Adcode 不完整,都算已发布)。
- `Deliverables`:
  - Post URL 是 `instagram.com/...` → `1 reel`
  - Post URL 是 `tiktok.com/...` 或 `vt.tiktok.com/...` → `1 TK`
  - 缺 Post URL 时,看正文/上下文能不能明确判断平台(提到"IG"/"Instagram"/"Reel" 按 IG 算;提到
    "TikTok"/"TK" 按 TikTok 算),能判断就按上面规则填,判断不了就留空 + 消息标注
    `⚠️平台未判断,Deliverable留空`。

**完整记录(Adcode + Post URL 都有)**:
```
lark-cli base +record-upsert --base-token Dj0BbQHGKaiaFssqeWucIBIen8g --table-id tblP5ZPXXzKXibYU \
  --json '{"Adcode":"<adcode>","Post URL":"<url>","Product":[{"id":"<product_record_id>"}],"Month":"<Jan~Dec>","Deliverables":"<1 reel 或 1 TK>","Posted?":true,"Posting Date":"<yyyy/MM/dd>"}' --as user
```
产品未匹配时,`--json` 里不要带 `Product` 这个 key(留空,不要传空数组占位,避免覆盖成不确定的值)。
`Deliverables` 判断不了平台时,`--json` 里不要带这个 key。

**仅 Adcode 不完整记录(缺 Post URL,2026-07-22 新增)**:
```
lark-cli base +record-upsert --base-token Dj0BbQHGKaiaFssqeWucIBIen8g --table-id tblP5ZPXXzKXibYU \
  --json '{"Adcode":"<adcode>","KOL Name":[{"id":"<kol_record_id>"}],"Month":"<Jan~Dec>","Posted?":true,"Posting Date":"<yyyy/MM/dd>"}' --as user
```
不要带 `Post URL` 这个 key(留空,不要传空字符串占位)。`KOL Name` 只有识别成功时才带,识别失败就不带
这个 key(同样不要传空数组占位)。如果这条记录里恰好也提取到了产品名候选并匹配成功,也可以一并带上
`Product`(不冲突,可选)。`Deliverables` 同样能判断平台才带,判断不了就不带这个 key。

`+record-upsert` 不传 `--record-id` 就一定是新建,不会自动查重,所以第四步的去重检查不能省。

写入是逐条串行执行,出错就记录下来继续下一条,不要中断整批处理。

---

## 输出

消息内容格式统一(日期用 `YYYY-MM-DD`;**Campaign 这一行只有在该记录已有 Campaign 值时才出现,
没有就整行不显示,不留占位符**):

```
📌 [YYYY-MM-DD] Today's adcode

1. 链接: https://...
   Adcode: XXXXX
   产品: M2

2. 链接: https://...
   Adcode: YYYYY
   产品: ⚠️产品未匹配(原文:"GazelePro")

3. 链接: https://...
   Adcode: ZZZZZ
   产品: Gorilla
   Campaign: Independence
   ↩️已存在,跳过(Base 中已有相同 Adcode)

4. Adcode: WWWWW
   网红: Terrell and Jarius
   ⚠️缺 Post URL,已写入 Base(网红已标注),麻烦回邮件跟对方要一下链接

5. Adcode: VVVVV
   网红: ⚠️未能识别发件人
   ⚠️缺 Post URL,已写入 Base,麻烦回邮件跟对方要一下链接

⚠️信息不全,未写入 Base:
- 原文片段:"...只有链接没有adcode..." → 缺 Adcode
```

规则:
- 完整且成功写入的记录按顺序编号列出,产品字段正常显示匹配到的 `Product Name`。
- 未匹配到产品的记录仍然写入(Adcode + Post URL),但产品那一行显示 `⚠️产品未匹配(原文:"...")`。
- 被去重跳过的记录也列出来,但加 `↩️已存在,跳过` 标注,方便吴双知道这条不是新写入的。
- **Campaign**:只有第四步查到该记录已有非空 Campaign 值时才加一行 `Campaign: <值>`(紧跟在产品
  行后面);新建的记录本技能不写 Campaign,天生是空的,不显示这一行。
- **仅 Adcode 不完整记录(缺 Post URL,2026-07-22 新增)**:不再放进"⚠️信息不全"分组,改为按顺序
  编号列在正常列表里,格式是"Adcode + 网红 + ⚠️缺 Post URL 提示",没有"链接"这一行(因为确实没有)。
  网红那一行:识别成功显示 KOL 姓名;识别到人名但 Base 里没匹配上显示该人名 + `⚠️网红未匹配 Base
  记录`;连人名都识别不到显示 `⚠️未能识别发件人`。
- "⚠️信息不全,未写入 Base"分组现在**专指"缺 Adcode"的记录**(不管 Post URL 有没有),这类记录依旧
  不写入 Base,单独放在消息末尾,不占前面的编号。

### Mode A(手动粘贴)的输出方式
直接在当前对话里用上面的格式回复,不走 `mcp__claw__notify`(吴双本人就在对话里,不需要额外推送)。
如果这批粘贴内容里一条有效链接/adcode都没提取到,直接回复"没有在这段内容里找到可识别的 IG/TikTok
链接或adcode,麻烦确认一下格式。"不写 Base。

### Mode 0(每日自动扫描)的输出方式
- 把这次扫描窗口内**所有候选邮件**提取出的记录,汇总成**一条**消息,用 `mcp__claw__notify` 推送
  (自动路由到吴双已连接的飞书私信,不需要手动查 open_id)。
- 如果这个时间窗口里**一封候选邮件都没有**(没有任何邮件看起来像 adcode 相关),**不发送通知**,
  避免每天骚扰;但仍然照常更新 `last-scan.md` 并写本地日志。
- 标题里的日期用 `scan_end` 对应的日期。
- 无论是否发送通知,都要写 `daily-log-DD-MM-YYYY.md`:记录扫描窗口(`scan_start` ~ `scan_end`)、
  扫了多少封邮件、多少封是候选、最终几条完整/信息不全/已存在跳过/产品未匹配,方便回溯"今天到底
  扫了没、扫到了什么"。

---

## Scheduling

| Job 名称 | Schedule | 说明 |
|---------|----------|------|
| Daily adcode email scan | `0 9 * * *`(每天,不分工作日/周末,09:00 BJT) | 运行 Mode 0 |

不要重复创建这个 cron job。如果吴双要求调整时间/频率,先用 `mcp__claw__cron` 的 `remove` 删掉旧的
再 `add` 新的(该工具没有 update 动作)。

---

## 边界 / 不做的事

- `KOL Name` 只在"Adcode 有、Post URL 缺"这一种不完整记录场景下才尝试写入,其余场景(完整记录、
  去重命中的已存在记录)一律不碰、不建、不改 KOL 关联(那是别的流程的事)。
- 不写 Pay Rate / Payment Date / Payment Status / KOL Contract / Payment done? 这些财务与合同字段。`Month`/`Deliverables`/`Posted?`/`Posting Date` 从 2026-07-24 起改为常规写入字段(见"写入 Base"一节),不再属于不写清单。
- Campaign 只读不写:本技能从不设置这个字段,但推送消息时如果记录已有 Campaign 值就带出来展示。
- 不新建 Product 表或 ALL KOLs 表里的记录 —— 匹配不到就是匹配不到,标注给人看,不自动新建产品/
  网红条目(避免库被写脏)。
- Mode 0 不做关键词粗筛(不加 `--query`),直接拉时间窗口内全部邮件,人工判断哪些是候选,避免因
  为措辞差异漏掉真正的 adcode 邮件。
- Mode 0 发现"缺 Adcode"的信息不全、或产品/网红未匹配时,只标注,不主动提议起草回复邮件或联系
  KOL。
- 已写入 Base 的"仅 Adcode"不完整记录,如果后续同一 Adcode 又出现带 Post URL 的新邮件,目前**不会
  自动回填**补全旧记录(见第四步"已知限制"),需要吴双另外提出才加这个能力。

