# 易秒办红线与边界

本文件汇总易秒办业务域**不可违反**的红线，供写操作/消息展示前自查。写协议（prepare→apply、continuation、停止条件）见 [`msg-write.md`](msg-write.md)、[`ding-write.md`](ding-write.md)、[`group-write.md`](group-write.md)；共享层通用规则见 `weaver-e10-shared`。

## 红线（违规 = 必须停下说明，不绕过）

1. **请求体禁止操作人字段**：任何 operation 的输入都不接受 `user`/`sender`/`creator`/`operator` 等操作人字段；操作者由会话 `eteamsid` 识别。不要在入参里补这些字段，CLI 会直接拒绝（`forbidden_keys`）。
2. **人名一律走 hrm**：姓名解析（消息发送者、群成员、阅读人、@提及）只认 `im.person.resolve`/`resolveByIds`（底层 `/api/hrm/common/getEmployeeByIds`）或消息行里的 hrm 姓名；**禁止用 IM 群成员接口返回的 `name` 字段**展示姓名，禁止本地猜测/拼表。
3. **uid/cid/群 id 非 0、按字符串传输**：uint64 必须字符串化；`0`、空串直接拒绝。
4. **不本地过滤、分页口径固定**：搜索/筛选一律服务端完成（`mask`/`cond`/`type` 等），**禁止先拉数据再本地过滤**；唯一例外是 `session.list` 的 `type`（接口本身不支持类型条件，CLI 与源脚本同为本地筛选，属于模块既定行为，不要据此扩展到其它字段）。分页口径固定：**有界区间**（时间范围 / 默认当天 / 显式 `end`）由 CLI 自动循环翻页拉完（上限 100 页），直接展示即可；**无界区间**（`latest:true`）只拉一页，需要更早数据时用 `nextStart` 显式续拉，同一轮内不要连续多次续拉；**会话列表不自动翻页**，用 `nextMsgid` 显式续拉。
5. **时间范围查询转 id 区间 + 强制收敛 7 天**：单聊/群聊/系统消息历史不支持服务端时间过滤，CLI 把 `from/to` 换算为消息 id 区间；跨度 > 7 天自动收敛为该范围最后 7 个自然日，`rangeShrink.notice` **必须原样转述给用户**；要更早历史就按 ≤ 7 天分段，不要替用户改口径。
6. **本人 IM 身份只用于本机组装**：`group.search` 的 `members/owner/creator` 条件、撤回/必达消息体、建群自检、消息「我」的判定，由 CLI 用 `teamsCheck` 取得的本人 `imCid`/`imUid` 完成；调用方不要传、也传不了这些身份（`user`/`sender`/`operator` 会被 `forbidden_key` 拒绝），不要自行拼 `cid`/`uid` 顶替。
7. **消息展示完整不截断**：拉到的 `content` 完整展示，无论多长；不得自行截断/省略/改写正文。输出顺序为最新在前；渲染表格时转义 `|`、保留换行提示（⏎）、媒体显示为 `[图片]/[视频]/[文件]名称` 且预览/下载链接保持可点击，必达消息保留 `[必达]` 前缀。
8. **写操作只认 CLI 签发的 continuation**：不手工拼、不复用、不跨操作；prepare 后 10 分钟有效；`apply` 不自动重试。
9. **禁止发送空白消息**：`txt` 为空或全空白（空格/换行）不算内容，CLI 直接返回 `content_required`，需提示用户提供非空内容。
10. **超时即失败**：普通请求超过 15 秒即视为失败（上传 15/60 秒），不再重试，向用户说明失败原因；禁止无限重试或静默换接口。
11. **未匹配不猜测**：人员/群未匹配（`total=0`/空）时直接告知「未找到『XX』，请确认名称是否正确」并停止。🔴 禁止翻历史会话、拉会话列表、按相似名/部分名模糊搜索去猜人，也不要推荐"可能的人"。
12. **禁止拉全量获取数量**：不允许通过逐页拉全量统计消息总数/会话总数等；触发此类需求（如"一共有多少条消息"）直接回复「无法统计总数，功能暂时不支持」，不提供逐页全量变通。数量只基于本次返回（如 `total=N`）。**有界区间的自动翻页只服务于"按范围取数据"，同样不能用来做全量计数。**
13. **旧字段兼容要显式**：`file.upload` 的旧名 `filePath`/`shareGroups` 仍可用，但与新名 `file`/`shareGroup` 同时出现且取值不一致时返回 `alias_conflict`；只保留一个，不要依赖"后者覆盖前者"。
14. **数据对不上不得自行猜测**：接口返回与预期不符（返回 0 条/条数不符/字段缺失）时，按下面模板先给证据再让用户选方向；禁止自作主张换参数反复探测、换同类型接口或编造数据。

## 写链停止条件

遇到以下任一情况立即停止写流程，先向用户说明再做只读回查，不静默重试：

- 返回 `partial` / `write_uncertain`（结果未知）。
- 网络中断 / 超时（可安全重试的只有 prepare 这类纯只读准备）。
- `apply` 已发出但响应丢失。
- 回查手段：单聊/群聊用 `msg.sync.single`/`msg.sync.group`（`latest:true`）看是否已发出；群状态用 `group.info`/`group.users`；必达可用系统消息或群置顶辅助确认。

## 已知禁用边界

- 不实现"已读回执的主动标记/已处理系统消息"这类状态回写（CLI 未暴露，避免伪装处理）。
- 不支持删除/清空消息、编辑已发消息：只能撤回**本人**消息（`msg.withdraw`，有时限）。
- 不支持建非普通群（部门群/全员群/事项群等）：`group.create` 只建普通群（type=0）。
- 不支持统计消息总数/会话总数（见红线 11），也不做消息统计分析/报表。
- 不支持定时推送、机器人托管、自动回复；跨平台 IM（企业微信/钉钉/邮件）请改用对应技能，不代为调用。
- 不支持"按接口未支持的字段做本地过滤"（免打扰/未读/发送人等）：接口不支持就如实告知，引导改用原生参数（`flag`/`deal`/`type` 等）。
- 移动端打卡、定位、设备凭证等与本域无关，不在此列。
- `schema` 之外的接口路径一律不可直接调用；禁止 Agent 绕过 CLI 拼 `/api/em/msg/executeIm/...` 等原始请求。

## 数据对不上提问模板（配合红线 12）

```
已确认事实：<接口返回码、条数、关键字段>（如「querySysMsgInfo group=110 返回 code=0，0 条」）
差异：接口返回 <X>，会话/预期显示 <Y>（如「会话列表显示未读 58 条」）
可能方向（需你选择，我不替你决定）：A <方向1> B <方向2> C <方向3>
```

## 常见错误码速查

| 码/type | 含义 | 处理 |
| --- | --- | --- |
| `1303` | 无聊天记录 | 按成功空列表（看 `emptyReason`），不报错 |
| `1209` / 群不存在 | 群不可读/已解散 | 告知用户 |
| `forbidden_keys` | 传了操作人字段 | 去掉后重试（说明红线） |
| `alias_conflict` | 旧字段与新字段同时出现且取值不一致 | 只保留其中一个后重试 |
| `self_identity_missing` | 需要本人 cid/uid 的查询取不到有效身份 | 说明登录态不完整，按共享规则重新登录 |
| `context_mismatch` / `continuation_expired` | 会话/租户或超时变化 | 重新 prepare |
| `target_changed` | prepare 后目标/内容指纹变化 | 重新 prepare |
| `members_resolve_failed` | 成员 hrm 解析失败 | 列失败项，问是否 `removeFailed:true` |
| `source_not_found` / `source_invalid` / `unread_empty` | 转必达源消息缺失/无未读人员 | 说明后由用户决定是否改发全员 |
| `content_required` / `content_conflict` | 内容为空或同时传了 img+file | 补非空内容/一次只发一种媒体 |
| `output_exists` / `output_parent_missing` | `file.download` 目标已存在/父目录不存在 | 换路径或先建目录，不覆盖既有文件 |
| 其他码（群 12xx / 消息 15xx / 数据 13xx） | — | 对照 [`error-codes.md`](error-codes.md) 解释并告知用户 |
