Files
dingtalk-workspace-cli/docs/lark-im-vs-dws-multi-im-design-review.md
T

863 lines
46 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.
# Lark IM 与 DWS Multi IM Skill 设计对比
> 状态:设计评审
>
> 日期:2026-08-03
>
> DWS Git 基线:分支 `codex/multi-im-optimization`,HEAD
> `017258e5b49517e3787a3d373f90953c128eaf58`
>(`feat(im): optimize Multi IM golden routes`)
>
> 工作区口径:评审时除本文档为未跟踪文件外,DWS 业务代码、Skills、references
> 和 scripts 均与上述 HEAD 一致;因此“当前实现”指该提交,不指远端默认分支。
>
> 对比基线:当前工作区中的 DWS Multi IM 实现,以及本机安装的
> `lark-im`、`lark-shared`、`lark-contact`、`lark-event` Skills
>
> 评审范围:Skill 根入口、shared 契约、目标解析、发送/读取/搜索、群聊、
> 消息资源、卡片、事件、Schema 元数据、task references 与配套脚本
> 实施后说明:本文是对上述提交的历史基线审计,其中“当前问题”、旧脚本路径和
> 文件数统计不代表优化后工作树。实施结果与完成口径见
> [DWS Multi IM 优化方案](dws-multi-im-optimization-plan.md)。被退役脚本的链接作为历史证据保留,
> 不应再被当作可执行入口。
## 1. 执行摘要
当前 DWS Multi IM 的主链设计比 `lark-im` 更适合 Agent 执行:
- 根 Skill 更小,只保留 Golden Route、不可推导的结果语义和按需导航;
- 人名、群名解析已经下沉到共享 typed resolver;
- 发送、读取、搜索、建群和事件 facade 能复用同一套消歧规则;
- 消息查询具有 `complete`、`hasMore`、`failures` 和资源下载 ledger,能够证明
结果是否完整;
- `event +listen-im` 能把自然目标和事件意图确定性编译为多个 EventKey,并复用
一个 consume 生命周期;
- 参数、安全、selection 与 interface 事实由 reviewed Schema 输入和 Runtime 交付,
不需要在根 Skill 复制完整参数表。
但当前实现只完成了“根 Skill 收敛”,还没有完成“整条文档链收敛”。进入第二层
reference 后,部分文档仍会把 Agent 带回手工查 ID、原子发送、原子建群和原子回复;
这些路径不仅增加步骤,还可能从带 `typed_yes` 门禁的 Golden Shortcut 切换到
`confirmation=not_required` 的原子 leaf。Shared 故障文档和三个遗留 Python 脚本也
存在同样的代际漂移。
总体判断:
```text
主链架构:DWS 更优
文档一致性:Lark 更优
任务闭环:DWS 高频路径更优,Lark 富媒体/Thread/Card 更完整
当前主要风险:DWS 子 reference 与脚本仍形成第二套执行语义
```
## 2. 对比方法与口径
本评审以实际文件和当前 CLI 合同为依据,不按命令名称做表面对齐。
事实优先级:
```text
当前 Cobra/Runtime
→ DWS leaf Schema 与 reviewed metadata/selection
→ 产品根 Skill
→ 精确 task reference
→ 全量原子参考与遗留脚本
```
Lark 侧重点读取:
- `~/.agents/skills/lark-im/SKILL.md`
- `~/.agents/skills/lark-shared/SKILL.md`
- `~/.agents/skills/lark-contact/SKILL.md`
- `~/.agents/skills/lark-event/SKILL.md`
- `~/.agents/skills/lark-im/references/`
- `~/.agents/skills/lark-event/references/lark-event-im.md`
DWS 侧重点读取:
- [`dingtalk-chat/SKILL.md`](../skills/multi/dingtalk-chat/SKILL.md)
- [`dws-shared/SKILL.md`](../skills/multi/dws-shared/SKILL.md)
- [`dingtalk-event/SKILL.md`](../skills/multi/dingtalk-event/SKILL.md)
- [`dingtalk-contact/SKILL.md`](../skills/multi/dingtalk-contact/SKILL.md)
- [`dingtalk-aisearch/SKILL.md`](../skills/multi/dingtalk-aisearch/SKILL.md)
- [`dingtalk-chat/references/`](../skills/multi/dingtalk-chat/references/)
- [`event-im.md`](../skills/multi/dingtalk-event/references/event-im.md)
- [`targetresolver`](../internal/shortcut/targetresolver/resolver.go)
- [`event +listen-im`](../internal/app/event_listen_im.go)
- [`chat` Schema registry/metadata/selection](../internal/cli/schema_hints/selection/chat.json)
### 2.1 当前文件体量
| 内容 | Lark | DWS Multi |
|---|---:|---:|
| IM 根 Skill | 249 行 / 21,524 bytes | 103 行 / 8,346 bytes |
| 正常 IM 强制 shared | 211 行 / 10,908 bytes | 0;最小契约内嵌 |
| IM references | 58 个 Markdown,5,336 行 | 9 个 Markdown,1,467 行 |
| IM scripts | 无 | 3 个 Python,565 行 |
| Event 根 Skill | 156 行 / 10,848 bytes | 100 行 / 7,521 bytes |
这组数字不能单独证明设计质量,但能够说明两套系统的基本取向:
```text
Lark:操作手册 + 显式 API/Scope Catalog
DWS:意图编译器 + Runtime/Schema 合同
```
## 3. 根 Skill 逐段映射
### 3.1 Frontmatter 与产品边界
`lark-im/SKILL.md` L1–13:
- 声明 Skill 版本、CLI bin 和 `cliHelp`;
- 将消息、群聊、文件、Reaction、卡片、Feed、Flag 和短信/电话加急都归入 IM;
- 强制先完整读取 `lark-shared`。
[`dingtalk-chat/SKILL.md` L1–14](../skills/multi/dingtalk-chat/SKILL.md#L1):
- 声明 DWS 最低版本、产品分类和 CLI bin;
- 明确把紧急 DING/短信/电话切到 `dingtalk-misc`,邮件切到 `dingtalk-mail`;
- 不要求正常单产品任务完整读取 `dws-shared`。
判断:DWS 的产品边界更清楚;Lark 的 IM 边界更宽,但因此根文件承担更多平台概念。
### 3.2 对象模型
`lark-im/SKILL.md` L15–34 在根文件定义:
- Message;
- Chat;
- Thread;
- Reaction;
- Flag;
- Feed Shortcut;
- Feed Group;
- Chat → Message/Member → Thread/Reaction/Resource 的对象关系。
DWS 根 Skill 没有完整对象树,只在
[`dingtalk-chat/SKILL.md` L71–78](../skills/multi/dingtalk-chat/SKILL.md#L71)
保留无法从普通 leaf 参数推导的关键区别:
- `openTaskId` 不是消息 ID;
- 子消息使用自己的 `messageId`;
- Favorite、消息 Pin、消息 Top、会话 Top 不是同一对象。
判断:Lark 更适合首次理解平台;DWS 更节省根上下文,但对象语义分散到多个
reference 和 Runtime DTO。
### 3.3 Shared 与身份
`lark-im/SKILL.md` L38–42 和 `lark-shared/SKILL.md` L48–87 显式解释:
- `--as user` 使用 UAT;
- `--as bot` 使用 TAT;
- app scope、用户授权、群成员关系和租户边界共同决定是否成功;
- bot 缺 Scope 与 user 缺 Scope 的恢复路径不同。
DWS 通过
[`runtime-contract.md`](../skills/multi/dws-shared/references/runtime-contract.md)
强调:
- 解析、读取和写入使用同一 profile;
- 不跨组织复用 `userId`、`openDingTalkId`、`openConversationId`;
- 是否确认以最终 Runtime gate 和 Schema 为准。
具体 user/bot/webhook 能力矩阵不在根 Skill 展开,而由 `+messages-send` 的 leaf
Schema 与 Runtime 校验。
判断:DWS 的 typed 交付更可维护,Lark 的身份故障解释更直接。
### 3.4 消息富化与资源
`lark-im/SKILL.md` L44–59 把下列事实直接放在根 Skill:
- sender name 由服务端返回,不额外查询 contact;
- 四个消息读取 Shortcut 默认附加 reactions 和编辑后的 `update_time`;
- 三个读取 Shortcut 支持 `--download-resources`;
- 资源按 `(message_id, file_key)` 去重、并发下载、单项失败隔离。
DWS 在
[`dingtalk-chat/SKILL.md` L71–77](../skills/multi/dingtalk-chat/SKILL.md#L71)
只保留任务级结果语义:
- list/search/mget 共享稳定消息投影;
- 检查 `complete`、`hasMore`、`failures`;
- 下载失败进入 ledger,不丢弃已取得消息;
- 路径必须位于工作目录内,默认不覆盖,完成后原子落盘。
内部由 [`chatmsg`](../internal/shortcut/chatmsg/chatmsg.go) 维护
`im.message-list.v1`、reaction、`updateTime`、`resourceRefs` 和分页完整性。
判断:DWS 更强调“能否证明完整”;Lark 更强调字段来源、批量并发和缺字段语义。
### 3.5 卡片、音频与跨产品内容
`lark-im/SKILL.md` L61–75 在根文件声明:
- Interactive Card 发送前必须读取专用建卡 workflow;
- 卡片 callback 走 `card.action.trigger`;
- Opus 才能作为语音消息;
- Lark Doc 内容应以 `im-markdown` 读取后再用 Markdown 发送。
DWS 根 Skill只将流式卡片路由到 `+messages-send-card`,并把参数交给精确 leaf
Schema。当前 DWS 卡片是创建/流式更新模型,不等同于 Lark 任意 Interactive Card
JSON,也没有同等的 callback Skill 闭环。
判断:DWS 的根设计更紧凑;Lark 的卡片设计和回调闭环更完整。该差异属于真实平台
能力差异,不应通过复制参数伪装对齐。
### 3.6 Shortcut 发现
`lark-im/SKILL.md` L100–126 在根文件逐项列出 22 个高阶 Shortcut。
[`dingtalk-chat/SKILL.md` L28–60](../skills/multi/dingtalk-chat/SKILL.md#L28)
只说明当前有 97 个公开 Shortcut,并暴露:
- 8 条 Golden Route;
- 6 条次级直接入口;
- 完整 Catalog 仅作最后发现回退。
判断:
- 高频首次选路:DWS 更好;
- 低频能力人工浏览:Lark 更直接;
- DWS 必须保证精确 references 与 Golden Route 一致,否则隐藏全量 Catalog 后将缺少
可靠的第二层导航。
### 3.7 原生 API 与 Scope
`lark-im/SKILL.md` L128–249 继续列出原生 API 资源和完整 Scope 表;调用原生 API 前
要求先查询 Schema。
DWS 根 Skill不放原子 API 和 Scope 表,只在最后降级到
[`chat.md`](../skills/multi/dingtalk-chat/references/chat.md),并把参数、selection、安全和
interface 事实交给 reviewed Schema 输入。
判断:DWS 更符合单一事实源和防漂移目标;Lark 更方便人工排障,但静态权限表与参数表
的维护成本更高。
## 4. 相关 Skill 与子产品设计
### 4.1 Shared 冷启动
Lark 的每个 IM task reference 都重复声明必须先读 `lark-shared`。优点是身份、授权、
JSON envelope 和高风险 exit-10 协议随处可见;代价是高频任务反复加载同一大段文本。
DWS 把 11 行最小契约作为 authored source,通过
[`gen_skill_shortcut_sections.py` L193–210](../scripts/gen_skill_shortcut_sections.py#L193)
注入 Chat 与 Shared。正常 IM 只读产品根 Skill,认证、权限、profile 和未知错误才进入
Shared reference。
这是 DWS 相对 Lark 最明确的架构改进之一。
当前边界问题:生成器只注入 Chat 和 Shared,但
[`dws-shared/SKILL.md` L14](../skills/multi/dws-shared/SKILL.md#L14)
泛称“产品根 Skill 已内嵌最小执行契约”。Contact、AI Search 仍强制完整读取 Shared,
Event 则没有注入该 marker。这一描述应收窄为真实覆盖范围,或将注入机制推广到其它
明确需要独立冷启动的产品根。
### 4.2 Contact、AI Search 与目标解析
Lark 的姓名发送仍是两条业务命令:
```text
lark-contact +search-user
→ Agent 选择 open_id
→ lark-im +messages-send
```
群名读取同样先 `+chat-search` 再调用消息读取。
DWS 将确定性目标解析下沉到
[`targetresolver`](../internal/shortcut/targetresolver/resolver.go):
- `ResolveUser`;
- `ResolveChat`;
- `ResolveUsers`;
- `ResolveChats`;
- 稳定 ID 去重;
- exact/unique 匹配;
- `ambiguous` / `not_found` 结构化 candidates;
- 批量全量预检。
它被 `+dm`、`+send-to-group`、`+messages-send`、`+chat-messages`、`+search-msg`、
`+chat-create` 和 `event +listen-im` 复用。
判断:DWS 在高频 IM 目标解析上明显优于 Lark。Contact/AI Search 仍应保留给人员详情、
组织关系和独立搜索意图,但不应重新成为普通发消息的强制前置步骤。
### 4.3 Event
Lark Event 是跨产品通用控制面:
- 根 Skill 负责 list/schema/consume、ready、stdin、退出码和 jq;
- IM reference 维护 12 个 EventKey;
- 一个 consume 进程只接受一个 EventKey;
- 多事件由多个进程完成。
DWS Event 是个人 IM 专用产品,并增加
[`event +listen-im`](../internal/app/event_listen_im.go):
```text
kind + events + target
→ typed resolver
→ 确定 EventKey 集合
→ 一次 event consume 生命周期
```
DWS 能在一个进程中复用单 bus、多 consumer、ready marker、NDJSON、回滚和退出清理。
判断:
- 高频个人 IM 监听:DWS 更适合 Agent;
- 跨产品事件和任意 payload/jq 探索:Lark 更通用;
- DWS 不应复制 Lark 的“一 EventKey 一进程”限制。
### 4.4 子文件粒度
Lark 采用“一个高阶 Shortcut 一个 reference”的细粒度模式,并为卡片拆出 schema、
style、组件和 callback workflow。优点是加载后任务边界清晰,缺点是文件总数和总体积较大。
DWS 采用较少、较宽的子产品 reference:
- [`01-messaging.md`](../skills/multi/dingtalk-chat/references/01-messaging.md):任务级组合;
- [`chat-message.md`](../skills/multi/dingtalk-chat/references/chat/chat-message.md):消息、搜索、卡片、Reaction、Pin/Top/Favorite;
- [`chat-group.md`](../skills/multi/dingtalk-chat/references/chat/chat-group.md):群与成员;
- [`chat-bot.md`](../skills/multi/dingtalk-chat/references/chat/chat-bot.md):Bot 与 Webhook;
- [`chat-conversation.md`](../skills/multi/dingtalk-chat/references/chat/chat-conversation.md):会话状态;
- [`chat.md`](../skills/multi/dingtalk-chat/references/chat.md):全量原子降级。
这种粒度本身合理,但每个宽 reference 必须先重申自己负责的 Golden Shortcut,再把原子
命令放入明确的降级区。当前部分文件仍以原子命令作为正文主路径,导致加载 reference 后
发生路由反转。
### 4.5 子产品依赖闭包
这里的“相关子产品”按真实导航边定义:根 Skill、reference 或 Runtime 会把任务交给它,
而不是仅仅因为它也属于协作套件。
```mermaid
flowchart LR
U["用户 IM 意图"]
subgraph L["Lark"]
LI["lark-im:消息与群聊主产品"]
LS["lark-shared:强制冷启动"]
LC["lark-contact:姓名/邮箱 → open_id"]
LE["lark-event:实时事件"]
LD["lark-doc:文档正文 → im-markdown"]
CARD["lark-im/card:卡片编译子树"]
LI --> LS
LC --> LI
LE --> LI
LD --> LI
LI --> CARD
end
subgraph D["DWS Multi"]
DC["dingtalk-chat:消息与群聊主产品"]
DS["dws-shared:安装必带、故障按需读取"]
DP["dingtalk-profile:profile/组织选择"]
DA["dingtalk-aisearch:人员语义搜索"]
DT["dingtalk-contact:人员详情/精确手机号"]
DE["dingtalk-event:个人 IM 事件"]
DM["dingtalk-misc:DING/短信/电话"]
DX["drive/todo/calendar/mail:跨产品终点"]
DC -. "认证/权限/未知错误" .-> DS
DS --> DP
DA --> DT
DA -. "普通自然目标由 typed resolver 旁路" .-> DC
DT -. "资料查询后交接" .-> DC
DE --> DC
DC --> DM
DC --> DX
end
U --> LI
U --> DC
```
#### Lark 子产品逐项
| 子产品/子树 | 进入条件 | 合同所有者 | 与 IM 的关系 |
|---|---|---|---|
| `lark-im` | 消息、群、资源、reaction、flag、feed、urgent、card | IM 根 Skill + 精确 Shortcut reference + CLI | 主产品 |
| `lark-shared` | 所有 IM/Event 操作前 | 认证、user/bot、scope、JSON envelope、exit 10 | 强制前置;每个 IM task reference 再次提醒 |
| `lark-contact` | 姓名/邮箱目标、已知 ID 补资料 | `+search-user` / `+get-user` | 普通按姓名发消息仍需 `contact → im` 两步 |
| `lark-event` | 实时消息、reaction、群变化、card callback | 通用 `event consume` 生命周期 | IM 只是 12 个 EventKey 中的一个 topic;一 key 一进程 |
| `lark-doc` | 把文档正文作为消息发送 | `--doc-format im-markdown` | 内容生产者;IM 保持原文并以 Markdown 发送 |
| `lark-im/references/card` | 发送 `interactive` 卡片 | card schema、style、component、resource | 不是独立产品,但拥有独立编译/校验工作流 |
| `lark-openapi-explorer` | Contact 不覆盖的部门树/组织架构 | 原生 OpenAPI 探索 | 仅由 Contact 边界引出,不属于普通 IM 链 |
Lark 没有独立 profile 子产品。身份切换集中在 `lark-shared` 的 `--as user|bot`;紧急
应用内/短信/电话能力留在 `lark-im`,没有像 DWS 一样拆到 sibling Skill。
#### DWS Multi 子产品逐项
| 子产品 | 进入条件 | 合同所有者 | IM 链中的地位 |
|---|---|---|---|
| [`dingtalk-chat`](../skills/multi/dingtalk-chat/SKILL.md) | 消息、群聊、资源、Bot/Webhook、会话状态 | Golden Route + Runtime Shortcut + leaf Schema | 主产品 |
| [`dws-shared`](../skills/multi/dws-shared/SKILL.md) | 安装时始终附带;认证/权限/profile/confirmation/未知错误时读取 | 最小 Runtime 契约与故障导航 | 正常路径不冷启动,故障路径按需 |
| [`dingtalk-profile`](../skills/multi/dingtalk-profile/SKILL.md) | 多账号、多组织、切换 profile | profile/组织选择规则 | 由 shared 引出;保障解析、读取、写入同 profile |
| [`dingtalk-aisearch`](../skills/multi/dingtalk-aisearch/SKILL.md) | 姓名、工号、职责、上下级、部门语义搜索 | 人员语义候选 | 普通 DM/群目标已由 Chat typed resolver 内化,不再是强制前置 |
| [`dingtalk-contact`](../skills/multi/dingtalk-contact/SKILL.md) | 已知 ID 补详情、完整手机号、部门/角色 | 精确通讯录事实 | 作为资料查询/低层 ID 补全 sibling |
| [`dingtalk-event`](../skills/multi/dingtalk-event/SKILL.md) | 监听消息、reaction、已读、撤回、群生命周期 | `+listen-im` 与 `event consume` | 个人 IM 实时入口;回复交回 Chat |
| [`dingtalk-misc`](../skills/multi/dingtalk-misc/SKILL.md) | DING、短信、电话、班级群 | Misc 内部的 Ding 等 reference | Chat 明确排除,产品边界比 Lark 更窄 |
| [`dingtalk-mail`](../skills/multi/dingtalk-mail/SKILL.md) | 用户目标是邮件 | Mail Skill | Chat 边界排除 |
| [`dingtalk-drive`](../skills/multi/dingtalk-drive/SKILL.md) | 查询群钉盘/群文件 | Drive Skill | 先由 Chat 取 `spaceId`,再交给 Drive |
| [`dingtalk-todo`](../skills/multi/dingtalk-todo/SKILL.md) | 消息转待办 | Todo Skill | Chat 读取真实消息上下文后交接 |
| [`dingtalk-calendar`](../skills/multi/dingtalk-calendar/SKILL.md) | 消息转日程 | Calendar Skill | Chat 读取时间、地点、参会人后交接 |
不应把 `dingtalk-dev` 计入日常 IM 数据链。它管理应用、机器人配置或开发控制面;当前
Chat 根 Skill 和精确 task references 没有把普通消息任务路由到它。
### 4.6 Multi 安装与发布边界
DWS Multi 不只是仓库里的文档目录,它有独立交付边界:
1. [`skills/embed.go` L23–29](../skills/embed.go#L23) 将 `mono` 与 `multi` 整棵目录嵌入
二进制,包含 references 和 scripts;
2. [`skill_setup.go` L77–95](../internal/app/skill_setup.go#L77) 将 multi 标记为
`EXPERIMENTAL/Preview`,支持按子 Skill 安装;
3. [`skill_setup.go` L139–156](../internal/app/skill_setup.go#L139) 即使用户只选 Chat,也会
强制附带 `dws-shared`;
4. 安装采用 additive 语义,不删除未列出的已安装 sibling Skill;
5. Release 的 `dws-skills.zip` 同时携带根部兼容 mono、显式 `mono/` 和完整 `multi/`。
这带来一个重要设计结论:Multi reference/script 是真实发布产物,不能按“开发辅助文件”
处理。但当前 Agent Schema 生成的 Markdown evidence 入口仍主要是 `skills/mono/`;Multi
文档并不会因为 Schema 生成成功就自动证明自己与 Runtime 一致。这正是第二层漂移需要
独立 policy gate 的原因。
## 5. References 逐文件对比
### 5.1 Lark IM references 全量清单
Lark IM 共 58 个 Markdown reference:顶层 26 个,Card 子树 32 个。根 Skill 直接链接
全部 21 个 Shortcut task reference,并另外链接 enrichment、reaction、feed 原子合同和
card workflow。它的基本单元是“一个任务/一个 Shortcut/一个精确合同”。
| 顶层 reference | 行数 | 职责 | DWS 对应/差异 |
|---|---:|---|---|
| `lark-im-card-action-reply.md` | 175 | `card.action.trigger` 监听、解析、回卡 | DWS 无等价 callback Skill 闭环 |
| `lark-im-chat-create.md` | 162 | 建群、身份、owner、成员、输出 | `+chat-create` + `chat-group.md`;DWS 自然成员解析更强 |
| `lark-im-chat-identity.md` | 55 | 群主、user/bot 操作者判断 | DWS 分散在 profile、Schema identity 和 Runtime |
| `lark-im-chat-list.md` | 166 | 当前身份加入的会话、排序、分页、mute | DWS 会话/群列表 Shortcut 与 `chat-conversation.md` |
| `lark-im-chat-members-list.md` | 83 | users/bots 分桶与截断语义 | DWS `group members`;无同等独立 truncation reference |
| `lark-im-chat-messages-list.md` | 157 | 单会话消息、thread 展开、资源、分页 | DWS `+chat-messages`;更强调 complete/failures ledger |
| `lark-im-chat-search.md` | 142 | 按关键词/成员搜群、mute、分页 | DWS `+chat-search` 或目标 resolver |
| `lark-im-chat-update.md` | 84 | 群名/描述更新与身份边界 | DWS group rename/settings;没有统一精确 task reference |
| `lark-im-feed-group-list-item.md` | 68 | 列出标签内 feed cards | DWS category list-conversations,平台语义不完全相同 |
| `lark-im-feed-group-list.md` | 65 | 列出 feed groups | DWS category list |
| `lark-im-feed-group-query-item.md` | 44 | 按 ID 查标签成员 | DWS category batch/list-by-conv,仅近似映射 |
| `lark-im-feed-groups.md` | 452 | Feed Group 原子 API、枚举、规则、scope | DWS `chat-conversation.md` 的 category 族;不应字段级复制 |
| `lark-im-feed-shortcut-create.md` | 97 | 会话 Feed 置顶、批量结果 ledger | DWS conversation set-top,缺少同粒度 task reference |
| `lark-im-feed-shortcut-list.md` | 103 | Feed 置顶列表与 detail enrichment | DWS `+conversation-list-top` |
| `lark-im-feed-shortcut-remove.md` | 48 | 取消 Feed 置顶与幂等语义 | DWS set-top off |
| `lark-im-flag-cancel.md` | 67 | message/feed 两层 flag 的 best-effort cancel | DWS Favorite/Top 对象不同,不应机械对应 |
| `lark-im-flag-create.md` | 67 | 创建 message/feed flag 与合法组合 | DWS Favorite/消息 Top 仅部分近似 |
| `lark-im-flag-list.md` | 101 | flag 排序、分页上限、thread enrichment | DWS list-favorites 等分散能力 |
| `lark-im-message-enrichment.md` | 54 | reaction、更新时间、thread、资源富化合同 | DWS 根结果语义 + `chatmsg` Runtime;不是独立 reference |
| `lark-im-messages-mget.md` | 99 | 最多 50 条批量消息详情 | DWS `+messages-mget` |
| `lark-im-messages-reply.md` | 277 | 安全、内容格式、媒体、thread reply、返回值 | DWS `+messages-reply` 当前只覆盖较窄文本引用回复 |
| `lark-im-messages-resources-download.md` | 94 | 资源 key、8 MB 分块、扩展名检测 | DWS `+messages-resource-download`;本地安全/ledger 更强 |
| `lark-im-messages-search.md` | 234 | 搜索、自动二步富化、分页、报告生成 | DWS `+search-msg`;typed target 与完整性更强 |
| `lark-im-messages-send.md` | 279 | user/bot 发送、内容格式、媒体、mention、返回值 | DWS `+messages-send`;平台能力矩阵不同 |
| `lark-im-reactions.md` | 299 | reaction CRUD/batch、完整 emoji enum | DWS reaction/文字表情分散在 `chat-message` + emoji 表 |
| `lark-im-threads-messages-list.md` | 115 | thread ID 来源、分页、资源 | DWS `+thread-replies`,当前主要是 reader |
Card 的 32 个子文件不是普通“补充说明”,而是一个内嵌小型子产品:
| 层 | 文件数 | 文件 | 设计职责 |
|---|---:|---|---|
| 工作流 | 1 | `lark-im-card-create.md` | 强制生成/校验/发送流程;禁止手写卡片 payload |
| Schema | 1 | `card-2.0-schema.md` | 卡片 2.0 可用组件及嵌套关系 |
| Style | 1 | `lark-im-card-style.md` | 版式、层级、间距、视觉规范 |
| Components | 27 | `button`、`chart`、`checker`、`collapsible_panel`、`column_set`、`date_picker`、`div`、`form`、`header`、`hr`、`img`、`img_combination`、`input`、`interactive_container`、`markdown`、`multi_select_person`、`multi_select_static`、`overflow`、`person`、`person_list`、`picker_datetime`、`picker_time`、`recycling_container`、`select_img`、`select_person`、`select_static`、`table` | 每组件合法字段、枚举、嵌套和示例 |
| Resources | 2 | `colors.md`、`icons.md` | 受控视觉枚举 |
DWS 当前只有流式卡片发送/更新命令和 `chat-message.md` 中约 10 行说明,没有对应的卡片
Schema/组件/风格/callback 子树。因此卡片差异不是“少写几篇 reference”,而是缺少一个
可独立审计的卡片编译层。
### 5.2 DWS Chat references 全量清单
| reference | 行数 | 当前角色 | 主要问题 | 建议归宿 |
|---|---:|---|---|---|
| [`01-messaging.md`](../skills/multi/dingtalk-chat/references/01-messaging.md) | 76 | Golden Route 不能单步覆盖时的任务编排 | 与根路由总体一致 | 保留为任务级主 reference |
| [`chat-emoji-list.md`](../skills/multi/dingtalk-chat/references/chat-emoji-list.md) | 209 | 199 个默认表情枚举 | 静态大表;易随平台漂移 | 若 Runtime 可查询则生成,否则加来源/更新时间门禁 |
| [`intent-guide.md`](../skills/multi/dingtalk-chat/references/intent-guide.md) | 51 | 低频意图与对象层级消歧 | 与根路由一致 | 保留,继续限制为低频加载 |
| [`lite-recipes.md`](../skills/multi/dingtalk-chat/references/lite-recipes.md) | 5 | recipe 导航壳 | 只重定向到 `01-messaging`,价值很低 | 合并或删除,减少无效跳转 |
| [`chat.md`](../skills/multi/dingtalk-chat/references/chat.md) | 363 | 原子能力总索引与回退 | 前 20 行说 Shortcut 优先,后续大量意图表又把原子命令设为默认 | 降级为纯 Catalog/原子 fallback,不再承担任务选路 |
| [`chat-message.md`](../skills/multi/dingtalk-chat/references/chat/chat-message.md) | 269 | 消息、搜索、卡片、reaction、资源 | L23 起重新以原子 send 为主;reply 也回退原子路径 | 先列对应 Shortcut,再隔离原子特殊字段区 |
| [`chat-group.md`](../skills/multi/dingtalk-chat/references/chat/chat-group.md) | 215 | 群、成员、公告、设置、身份 | L32 起以原子建群为主,L186 再次手工搜人 | `+chat-create` 为默认;管理原子命令保留 |
| [`chat-bot.md`](../skills/multi/dingtalk-chat/references/chat/chat-bot.md) | 139 | Bot/Webhook、机器人进群/撤回 | L11 与根 `+messages-send --as bot/webhook` 直接冲突 | 统一发送走 Shortcut;专属管理能力保留 |
| [`chat-conversation.md`](../skills/multi/dingtalk-chat/references/chat/chat-conversation.md) | 140 | 会话状态、Top、mute、category | 仍手工 `aisearch → conversation-info`,部分能力缺 Shortcut 首选说明 | 按对象层级列高阶入口;原子管理作为细节 |
DWS 的优点是只有 9 个 Chat reference,Agent 不必在 58 个文件中发现入口;缺点是每个
文件跨度过宽,任务级路由、原子 Catalog、参数表、工作流和错误处理常在同一文件内混合。
Lark 的精细拆分值得吸收,但不必照搬“一 Shortcut 一文件”到所有 97 个 Shortcut。
### 5.3 相关子产品 references
| 子产品 | reference/script 规模 | IM 实际读取点 | 评审结论 |
|---|---|---|---|
| `dws-shared` | 12 个 reference:`runtime-contract`、`routing`、`workflow-routing`、`global-reference`、`error-codes`、`capability-limits`、`channel-login`、`url-patterns`、`intent-guide` 和 3 个 common recipe/convention 文件 | 正常 Chat 不预读;错误、跨产品或 URL 不明时精确进入 | 分层正确,但 `global-reference`/`error-codes` 已有 Runtime 漂移 |
| `dingtalk-event` | 1 个 `event-im.md`,399 行 | 群生命周期、精确 EventKey、Filter、订阅运维/排障 | 单文件过宽;高频已回根,建议再拆 lifecycle/filter/ops |
| `dingtalk-contact` | 5 个 reference + 1 个 `contact_dept_members.py` | 人员资料、完整手机号、部门/角色;不是普通 DM 必经 | 根 Skill 仍重、仍优先脚本;与 Chat 新 resolver 代际不同 |
| `dingtalk-aisearch` | 3 个 reference,无脚本 | 语义找人、跨源检索 | 对独立搜索正确;不应回流为 Chat 普通自然目标前置 |
| `dingtalk-profile` | 规则集中在根 Skill | 多组织/profile 消歧 | 应由 shared/Runtime 统一,不应复制到每个 Chat reference |
Lark 相关 sibling 的规模更小:`lark-contact` 只有 2 个 task reference,`lark-event` 的 IM
部分只有 1 个 86 行 reference;但它把较多通用生命周期合同放在各自根 Skill。DWS 则把
Event 的大量运维细节放入一个 399 行 IM 文件,两侧“文件数”不能脱离根文件体量比较。
### 5.4 Reference 加载链结论
理想链路应满足:
```text
根 Skill 选意图
→ 一个精确 task reference 补充不可推导语义
→ leaf Schema 提供参数/安全/interface 真相
→ Runtime 执行
```
当前 Lark 基本符合这个形状,但根和 shared 更重;当前 DWS 根已经符合,第二层却常变成:
```text
根 Skill 选 Golden Shortcut
→ 宽 reference 重新选原子命令
→ 复制静态 flags/返回结构
→ 绕开原 Shortcut 的 resolver、DTO 或 confirmation gate
```
所以 DWS 的整改重点不是增加 reference 数量,而是让每个 reference 只拥有一种职责:
任务选路、平台语义、原子 fallback 或静态枚举,不能四者混合。
## 6. Scripts 逐文件对比
### 6.1 Lark IM scripts
`lark-im`、`lark-contact`、`lark-event` 当前均没有产品内 `scripts/`。这不是能力缺失:
- 自动分页、thread 展开、reaction 富化、资源下载、目标搜索等编排在 CLI Shortcut 内;
- 卡片生成通过 reference 驱动的 workflow 完成;
- Event 的长连接生命周期由 `event consume` 承担;
- 因而不存在“脚本自行解析 CLI JSON、再调用第二套原子命令”的旁路。
### 6.2 DWS Chat 产品 scripts
Multi Chat 的 3 个 Python 会随 `skills/multi` 一起嵌入二进制和发布包,即使根 Skill 与
references 没有导航到它们。它们不是未交付的草稿,而是“已交付但不可发现”的旁路。
| script | 行数 | 做什么 | 逐行级问题 | 建议 |
|---|---:|---|---|---|
| [`bot_broadcast.py`](../skills/multi/dingtalk-chat/scripts/bot_broadcast.py) | 112 | 对多个会话逐个调用机器人发送 | L92–99 直接调用原子 `send-by-bot`;仅以进程码/是否有 JSON 判断成功;无 profile、confirmation、幂等键、逐项 unknown ledger | 若真实需要批量能力,应下沉为 typed Runtime Shortcut;否则删除 |
| [`chat_export_messages.py`](../skills/multi/dingtalk-chat/scripts/chat_export_messages.py) | 230 | 搜群、翻页、导出 JSON | L88 默认 `groups[0]`;自行兼容多种旧 envelope;固定 `+08:00`;直接写任意输出路径;没有 `complete/failures/resource` 合同 | 已被 `+chat-messages --chat-query` 和任务结果合同覆盖,应删除或只做稳定 DTO 导出器 |
| [`chat_history_with_user.py`](../skills/multi/dingtalk-chat/scripts/chat_history_with_user.py) | 223 | 搜人、翻页、导出单聊 | L57 明示返回首项,L80 `users[0]`;还调用已不推荐的 `contact user search`;同样自行猜 envelope、固定时区和直接写文件 | 已被 `+chat-messages --user-query` 覆盖,应删除 |
还有一层副本漂移:同名脚本同时存在于 `skills/mono/scripts/` 和
`skills/multi/dingtalk-chat/scripts/`。`bot_broadcast.py` 当前字节一致;另外两个已经不同,
Multi 副本新增 `nextCursor` 与错误兼容,而 Mono 副本未同步。没有单一 authored source 或
生成门禁时,即使保留脚本,也会形成 mono/multi 两套行为。
### 6.3 DWS 仓库级相关 scripts
这些 scripts 不随单个 Chat Skill 作为操作 recipe 使用,但决定 Shortcut、Skill 文档、
测试证据和发布质量。应与产品脚本分开评审。
| script | 行数 | 角色 | 是否覆盖 Multi 第二层 |
|---|---:|---|---|
| [`gen_skill_shortcut_sections.py`](../scripts/gen_skill_shortcut_sections.py) | 253 | 从公开 Catalog 生成 Shortcut 区块,并把最小 Runtime contract 注入 Chat/Shared | 只改根 Skill 生成块,不改 Chat references/scripts |
| [`check-skill-context-budget.sh`](../scripts/policy/check-skill-context-budget.sh) | 109 | Chat/Event 根字节预算、必备 Golden Route、旧路由禁词 | 不扫描 references/scripts |
| [`check-skill-commands.sh`](../scripts/policy/check-skill-commands.sh) | 16 | 构建并运行 Skill 命令静态检查器 | 检查命令可解析,不证明首选路由/安全门禁一致 |
| `gen_shortcut_public_catalog.py` | 255 | 生成公开 Shortcut Catalog 和 Go 投影 | Runtime Catalog 层,不审文档加载链 |
| `gen_shortcut_test_matrix.go` | 316 | 通过真实 Cobra 树与 fake caller 装配全部 Shortcut | 证明命令装配,不审原子 reference 旁路 |
| `gen_shortcut_comparison.py` | 580 | 聚合 Shortcut 对比和测试 HTML | 报告生成,不是 policy gate |
| `gen_shortcut_backend_mcp_issues.py` | 237 | 汇总下层 MCP 对接问题 | Runtime 后端审计 |
| `gen_shortcut_error_review.py` | 449 | 将测试失败映射到修复位置 | 测试报告辅助 |
| `record_real_shortcut_run.py` | 135 | 记录真实 Shortcut 运行结果 | 单次证据采集 |
| `shortcut_real_result.py` | 480 | 统一解析真实运行的成功/失败事实 | 审计公共库,不供产品脚本复用 |
| `run_shortcut_real_write_matrix.py` | 455 | 真实写 Shortcut 矩阵 | 跨产品写审计 |
| `run_chat_shortcut_live_audit.py` | 1,162 | Chat 只读 Shortcut 真实链路审计 | Runtime 很深,但不扫描文档 |
| `run_chat_shortcut_live_write_audit.py` | 865 | Chat 真实写入/清理审计 | Runtime 很深,但不扫描产品 scripts |
| `run_chat_shortcut_write_dry_run_audit.py` | 1,101 | Chat 写 Shortcut dry-run 合同审计 | 证明 Shortcut 预览,不证明 reference 会选择它 |
因此当前 DWS 已有大量 Runtime/Shortcut 审计资产,真正缺的是很薄的一层“发布内容一致性”
检查,而不是再增加一个大型 live audit:
1. 枚举 Multi 根 Skill 的所有 reference 边;
2. 抽取 reference 和产品 script 中出现的 CLI path;
3. 与 reviewed selection、Runtime confirmation 和 Golden Route 对照;
4. 拒绝 `users[0]`/`groups[0]`、旧 envelope、未声明原子 fallback;
5. 检查 mono/multi 同名脚本是否来自单一源或明确允许差异。
## 7. 能力对比
| 场景 | 更强的一方 | 说明 |
|---|---|---|
| 按姓名/群名直接发送 | DWS | 一条业务命令完成解析、消歧和发送 |
| 自然目标读取、搜索和建群 | DWS | 共享 resolver、批量预检、结构化歧义 |
| 分页完整性与 partial result | DWS | `complete/hasMore/failures` 任务级合同 |
| 统一发送身份 | DWS | 一个 `+messages-send` 承载 user/bot/webhook 的真实子集 |
| Thread 自动展开 | Lark | list/mget 默认扩展 replies;DWS 使用单独读取入口 |
| 回复能力 | Lark | 支持 user/bot、媒体和 thread reply;DWS 当前只做用户纯文本引用回复 |
| 卡片创建与 callback | Lark | 建卡 workflow、Schema、自检和 `card.action.trigger` 完整 |
| 资源下载细节 | Lark | 8 MB 分块、扩展名检测和身份 Scope 描述更完整 |
| 下载安全与完整性 ledger | DWS | 相对路径、默认不覆盖、原子落盘、失败并入任务完整性 |
| 多事件 Agent 监听 | DWS | 多 EventKey、自然目标、单进程统一生命周期 |
| 通用跨产品事件 | Lark | 同一 Event Skill 覆盖 IM/Approval/Task/VC 等 |
| Scope/身份人工排障 | Lark | 根 Skill 与 shared 更显式 |
| 参数和安全防漂移 | DWS | reviewed registry + metadata + selection + generated Catalog |
| Feed/会话分类 | 不可直接比较 | 平台对象不同,不能只按名称映射 |
| 紧急短信/电话 | 产品边界不同 | Lark 放在 IM;DWS 放在 `dingtalk-misc` |
## 8. 当前设计漂移
### 8.1 高优先级:子 reference 把 Golden Shortcut 降级为原子写路径
根 Skill 已冻结以下入口:
```text
建群 → +chat-create
引用回复 → +messages-reply
高级/Bot/Webhook 发送 → +messages-send
```
但子 reference 仍保留相反的默认路线:
1. [`chat-group.md` L32–49](../skills/multi/dingtalk-chat/references/chat/chat-group.md#L32)
以 `chat group create` 为建群主入口;L186–192 又要求先手工执行 `aisearch person`。
2. [`chat-message.md` L23–68](../skills/multi/dingtalk-chat/references/chat/chat-message.md#L23)
以原子 `chat message send` 为发送主入口;L146–153 以原子 `message reply` 为引用回复。
3. [`chat-bot.md` L11–15](../skills/multi/dingtalk-chat/references/chat/chat-bot.md#L11)
强制所有 Bot 发送使用原子 `send-by-bot`;L75–86 继续推荐原子 Webhook。
4. [`event-im.md` L308–312](../skills/multi/dingtalk-event/references/event-im.md#L308)
自动回复仍调用原子 `chat message send`,与 Event 根 Skill 的 `+messages-send` 不一致。
这不是单纯的命令风格差异。当前 reviewed metadata 中:
- `+chat-create`、`+messages-reply`、`+messages-send` 为
`confirmation=user_required`、`runtime_gate=typed_yes`;
- 原子 `chat message send` 和 `chat message reply` 为
`confirmation=not_required`;
- 当前 leaf Schema 同样显示原子 group create、bot send、webhook send 为
`not_required`。
因此,加载低频 reference 可能让同一个用户意图切换到更弱的安全门禁,同时失去 typed
resolver、dry-run parity、稳定输出 DTO 或 continuation context。
### 8.2 高优先级:策略门禁只检查根 Skill
[`check-skill-context-budget.sh`](../scripts/policy/check-skill-context-budget.sh)
当前检查:
- 根 Skill 字节预算;
- Golden Route 必备字符串;
- 根 Skill 中的旧 `aisearch`、Webhook、媒体上传和 shared 冷启动模式;
- 根 Skill 是否重新展开完整 Shortcut 表。
它不扫描:
- `dingtalk-chat/references/**`;
- `dingtalk-event/references/**`;
- `dingtalk-chat/scripts/**`;
- reference 中的高阶入口与原子入口 confirmation 差异。
所以当前门禁可以通过,但无法证明整条 Skill 加载链一致。
### 8.3 高优先级:遗留 Python 脚本违反 typed resolver 原则
当前 Chat Skill 目录仍包含:
- [`chat_history_with_user.py`](../skills/multi/dingtalk-chat/scripts/chat_history_with_user.py);
- [`chat_export_messages.py`](../skills/multi/dingtalk-chat/scripts/chat_export_messages.py);
- [`bot_broadcast.py`](../skills/multi/dingtalk-chat/scripts/bot_broadcast.py)。
其中:
- `chat_history_with_user.py` 搜人后直接选择 `users[0]`;
- `chat_export_messages.py` 搜群后直接选择 `groups[0]`;
- `bot_broadcast.py` 逐群调用原子 `send-by-bot`,不复用统一发送合同;
- 三者均未被当前 Multi Chat 根 Skill 或 references 导航引用。
这些脚本形成孤立的第二套解析、分页、发送和错误处理系统,且直接违反“多候选禁止选择
第一项”的最小运行契约。
### 8.4 中优先级:Shared 故障文档已落后于 Runtime
[`global-reference.md`](../skills/multi/dws-shared/references/global-reference.md) 仍声明:
- `--format` 默认 table;
- JSON 成功统一为 `{"success":true,"body":...}`;
- 存在旧的全局 token 参数描述。
当前 CLI leaf Help 默认 JSON,Shortcut 又会输出各自的版本化 DTO。
[`error-codes.md` L65–70](../skills/multi/dws-shared/references/error-codes.md#L65)
仍声称 Chat text 是位置参数而不是 flag;当前 Runtime Help 明确推荐 `--text`。
正常 IM 不加载这些文件是正确的,但一旦发生认证或执行错误,Agent 恰好会被路由到这些
过期信息,因此故障路径的一致性仍然重要。
### 8.5 中优先级:Shared 注入范围与文案不一致
`dws-shared` 声称产品根 Skill 已从同一来源内嵌最小契约,但生成器当前只更新 Chat 与
Shared。Contact、AI Search 继续强制读取 Shared;Event 没有受控注入 marker。
两种方案都可以成立,但必须选择一种明确合同:
1. 文案收窄为“Chat 等已迁移产品根已内嵌”;或
2. 将 marker 与生成门禁推广到全部需要独立冷启动的产品根。
### 8.6 低优先级:Event 根仍保留较多运维细节
当前 Event 根 Skill 已由 254 行缩至 100 行,但仍包含:
- 16 个兼容 EventKey;
- ready marker 细节;
- `0/2/1` 重试预算;
- 本地订阅保护文件路径和权限。
这些内容本身正确,但与“根只保留高频入口,完整 EventKey/ready/retry 运维进入按需
reference”的目标仍有距离。可以根据真实误用率决定是否继续迁移,不应仅为缩短而删除
关键长连接安全信息。
## 9. 建议目标结构
### 9.1 保留 DWS 当前根设计
不要把 Lark 的完整 API、Scope 和 Shortcut 表复制回 DWS 根 Skill。目标结构继续保持:
```text
Frontmatter / 产品边界
→ 最小 Runtime 契约
→ Golden Route
→ 不可推导的结果语义
→ 精确 task reference 导航
→ 最短错误分流
```
### 9.2 吸收 Lark 的精确 reference 原则
每个 reference 开头都应先声明本文件负责的高阶入口:
```text
默认入口
→ 关键结果与安全语义
→ 平台限制
→ 只有需要原始响应/特殊下层能力时才进入原子降级
```
原子命令不应与 Golden Shortcut 并列为两个默认答案。
### 9.3 收敛子文件
建议按以下规则重写:
| 文件 | 默认高阶入口 | 原子命令保留条件 |
|---|---|---|
| `chat-message.md` | `+messages-reply`、`+messages-forward*`、`+messages-send-card`、`+flag-*` | 高阶入口未暴露的特殊字段或原始响应 |
| `chat-group.md` | `+chat-create`、群成员/设置对应 Shortcut | 无自然目标支持或 Shortcut 不覆盖的管理能力 |
| `chat-bot.md` | `+messages-send --as bot/webhook` | 多群广播、机器人撤回、入群等专属能力 |
| `chat-conversation.md` | `+conversation-list-top` 与对应 Shortcut | 低频分类/状态原子能力 |
| `event-im.md` | `+listen-im`、回复使用 `chat +messages-send` | 群生命周期、显式 EventKey、Filter DSL、订阅运维 |
### 9.4 处理遗留脚本
三种可选策略按推荐顺序排列:
1. 已由 Golden Shortcut 完全覆盖的脚本从 Multi 发布包删除;
2. 仍有价值的脚本改为调用 Golden Shortcut,并解析其稳定 DTO;
3. 只有 Runtime 暂时无法承载的批量流程才保留脚本,同时增加 typed candidates、
profile、confirmation、partial failure ledger 和测试。
禁止继续维护“脚本自己搜第一个候选、自己拼原子写命令”的模式。
### 9.5 增加跨文件门禁
在现有预算检查之外增加:
1. 扫描全部 `dingtalk-chat/**` 和 `dingtalk-event/**`,禁止已废弃默认路线回流;
2. 对每个 reference 中出现的写命令,验证它是否为该意图的 reviewed 首选入口;
3. 若 reference 从 gated Shortcut 降级到 ungated 原子 leaf,必须有精确的、可审核的
`fallback_reason`;
4. 禁止脚本使用 `results[0]`、`users[0]`、`groups[0]` 作为自然目标默认选择;
5. 校验根 Skill 导航的每个 reference 不会再次推荐与根相反的路径;
6. 校验 shared 输出、全局 flags 和错误 envelope 与当前 Cobra/Runtime 一致。
## 10. 不应照搬的 Lark 设计
以下设计只可作为能力启发,不应直接迁移:
- `open_id`、`chat_id`、`message_id`、资源 key 与 EventKey 名称;
- user/bot 完全对称的富媒体假设;
- 群 description、initial bot、visibility、指定 owner;
- Thread writer;
- Interactive Card 1.0/2.0 JSON 和 callback 结构;
- Lark Feed Group 与 DingTalk 会话分类的字段映射;
- 完整根文件、静态 Scope 表和全量 API Catalog;
- 每个 task reference 强制重新读取整个 shared;
- 多 EventKey 必须多进程的实现限制。
DWS 应继续遵守“迁移任务能力,不迁移平台假设”。
## 11. 建议实施顺序
### 第一阶段:修正文档安全漂移
1. 修正 `chat-group.md`、`chat-message.md`、`chat-bot.md`、`event-im.md` 的默认入口;
2. 原子写命令降级必须说明原因和门禁差异;
3. 修复 shared 的输出、flags、Chat 错误说明。
### 第二阶段:清理旁路
1. 删除或重写三个孤立 Python 脚本;
2. 增加禁止首候选和原子写回流的策略检查;
3. 把 references 纳入同一生成/漂移审计。
### 第三阶段:继续能力闭环
在下层真实支持后再评审:
- Thread writer;
- Bot 富媒体;
- 卡片 callback;
- 分块/断点资源下载;
- 更丰富的群创建参数。
这些能力未落地前继续通过 `avoid_when`、`availability` 和 `interface_reason` 明确限制。
## 12. 验证记录
本次评审执行了:
```bash
./scripts/policy/check-skill-context-budget.sh
go test ./internal/shortcut/targetresolver -count=1
go test ./internal/shortcut/chat ./internal/shortcut/smart ./internal/app \
-run 'Test.*(ListenIM|NaturalTarget|MultiSkill|MessageView|MessagesSend|MessagesReply|ChatCreate)' \
-count=1
go test ./internal/app -run '^(TestEventListenIM|Test.*ListenIM.*)$' -count=1
```
结果:
- Chat 根 Skill 8,346 bytes,低于 10,000 bytes 门禁;
- 最小 Runtime 契约 1,531 bytes,低于 3,000 bytes 门禁;
- 根 Skill 未重新展开 Shortcut 表;
- target resolver、Chat/Smart 相关测试与 Event listen-im 测试通过。
这些结果证明根路由、Runtime 主链和预算门禁已经成立,但现有门禁尚未覆盖本评审识别的
子 reference、shared 故障文档和遗留脚本漂移。
## 13. 最终结论
DWS Multi IM 已经从“Agent 手工编排多个原子命令”升级为“产品 Skill 选择任务入口、
CLI 完成确定性执行”的架构。相较 `lark-im`,它在高频目标解析、任务级完整性、Schema
单一来源和多事件监听上更先进;相较 Lark 的不足主要不是根设计,而是第二层内容尚未
完全迁移到新架构。
最有价值的下一步不是继续缩短根 Skill,也不是增加更多同义 Shortcut,而是消除所有
子文件和脚本中的第二套执行语义,使任意合法加载路径最终都收敛到相同的 Golden Route、
Runtime gate、typed resolver 和结果合同。