Archive 21 implemented triplets whose shipped decisions are complete and whose bodies no longer guide future work (one-off UI chrome, generator applications whose scripts are self-explanatory, superseded implementation detail, process history owned by current contracts/skills). Delete 4 rejected triplets whose premises are obsolete: the DeepReadonly proposal (dev-invariants note now carries the alternative inline), the collapse tool-owned presentation proposal (superseded by the shipped render-intent union), retire-mid-turn-steering (steering is now load-bearing across plan-mode/apiproxy/TUI), and single-session-ACP (automation-only ACP resolved the question; multi-session isolation is pinned by tests). Repair every inbound link: retarget intentional historical citations to archived paths, replace decision-current citations with the surviving authority, and fix the stale example-execute-over-tsx pointer in pnpm-workspace.yaml. Re-record pairing sidecars and seal the archive manifest (append-only; existing seals unchanged).
4.9 KiB
Agent Note: 针对 Cordis 对外服务接口的 JSDoc 完整性门禁
Status: implemented Archived: 2026-07-27
English | 中文
问题
生成的 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 的约定条目中,与 @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,而正文摘要不含标签。因此,源码编辑会同时刷新可读索引和签名旁展示的确切契约。