# Agent Note: 针对 Cordis 对外服务接口的 JSDoc 完整性门禁

Status: implemented
Archived: 2026-07-27

[English](2026-07-04-cordis-jsdoc-completeness-gate.md) | 中文

## 问题

生成的 Cordis 目录此前强制了事件分发模式，但未强制要求完整的服务与事件契约。方法可以缺少描述，参数或返回值可以在跨插件 API 接口上不写文档——而这恰恰是 IDE 引导最重要的地方。

AGENTS.md 中的规则（「每个导出都有解释语义的 JSDoc」）只能靠评审以行文形式检查；本仓库的既定偏好是将不变式编码为机械门禁。「Cordis 服务函数与事件」这一范围有精确的机器定义，只有目录生成器知道：事件是 `declare module 'cordis'` 内 `interface Events` 的成员，服务接口是每个 `interface Context` 键所指向的类的公开方法。ESLint 规则看不到这层映射；生成器在每次运行时计算它。

## 决策

扩展 `scripts/gen-cordis-catalog.ts`——复用同一次遍历和同一套 `@mode` 先例——对它编目的所有内容强制执行 JSDoc 完整性要求。`verify-cordis-catalog` 在 `doc-sync` 内运行，因此相关文档变更和 CI 会执行同一门禁，无需另行接线。

契约如下：

- **事件**需要描述性文字，以及为每个**载荷参数**提供非空的 `@param`。载荷参数是携带事件数据的签名参数；`this` 接收者注解和尾部的 waterfall（瀑布式事件） `next` 免检——`next` 是分发机制，其语义已由 `@mode waterfall` 标签（及其结构交叉检查）拥有，逐事件重述只是样板代码。为免检参数写文档是允许的；只有缺失才被检查。
- **服务类**需要类级 JSDoc，每个公开方法需要描述性文字、为每个参数提供非空的 `@param`，以及非空的 `@returns`——除非标注的返回类型是 `void`/`Promise<void>`（此时 `@returns` 可选——resolve 时机有时值得记录——但从不强制要求）。
- **陈旧标签报错**：`@param` 命名了一个不存在的参数即为违规，与 `@mode` 与签名矛盾的检查对称。标签描述必须非空；超出此范围的语义质量由评审负责。
- **遍历可检查的显式性**：门禁是纯 AST 遍历（不使用类型检查器），因此服务方法必须显式标注返回类型（推断的返回类型无法分类），接口参数必须是简单标识符（解构模式没有名称供 `@param` 匹配）。
- **违规聚合**为一条错误信息，列出所有违规项——修复时一次看到完整清单。此前快速失败的 `@mode` 检查也移入同一份聚合报告，消息文本不变。

生成器保留同一源码注释的两种视图：`parseJsDoc` 在第一个块标签处结束条目正文，而 `ts cordis-catalog` 签名块包含原始 JSDoc，并完整保留 `@param`、`@returns` 和 `@mode`。因此，读者可以看到完整的源码契约，而块标签文本不会泄漏到周围正文中。

`packages/core/agent/tests/gen-cordis-catalog.spec.ts` 中的负路径测试对合成 fixture（测试前置数据）运行 `collectEvents`/`collectServices`，验证每条守卫都会触发且免检规则成立。撰写规则写在根 [AGENTS.md](../../../../AGENTS.md) 的约定条目中，与 `@mode` 规则并列。

## 曾考虑的替代方案

- **ESLint 规则**：无法看到该范围的机器定义（哪些 `interface Events` 成员、哪些 `ctx.<key>` 类构成 Cordis 对外服务接口）；目录生成器在每次运行时恰好计算这层映射，因此门禁放在那里。
- **将每个方法展开为单独的正文小节**：否决。目录保留一个服务章节和一个签名块，以维持可扫读性；附着于每个声明的 JSDoc 则在原处保留完整的方法契约。
- **逃逸标签**：不设。该接口面小且经过策展（采纳时 12 个服务、57 个方法、27 个事件），要点在于检查不可豁免。

## 后果

- 新事件或服务方法不能带着未记录的参数或结果落地：生成器会拒绝重新生成，`verify-cordis-catalog` 也会使 `doc-sync` 和 CI 失败。采纳时发现的约 139 处缺口已在同一变更中补齐，因此门禁以绿色状态落地。
- 服务接口必须显式标注返回类型并使用标识符参数。两项约束在采纳时均未构成限制（所有方法已有标注；不存在解构的 seam 参数）；但二者现在是承重要求，违反时会被机械检测到。
- AGENTS.md 中通用的 JSDoc 规则（「一行能说清就用一行」）在此接口上获得了更严格的特例：仅当方法无参数且返回 void 时，一行摘要才足够。
- 为 `next` 或 `this` 写 `@param` 合法但不检查——这是有意的不对称：门禁强制载荷契约，拒绝要求样板代码。
- 每个生成的事件或方法片段都带有其原始 JSDoc，而正文摘要不含标签。因此，源码编辑会同时刷新可读索引和签名旁展示的确切契约。
