DeepSeek Harness 的 Cordis 对外 API JSDoc 完整性门禁:把「每个导出都有文档」编译为机械化的 CI 契约 DeepSeek Harness 的 Cordis 对外 API JSDoc 完整性门禁把「每个导出都有文档」编译为机械化的 CI 契约【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness本篇技术指南围绕 DeepSeek Harness 仓库中一项已落地implemented的工程决策展开如何为 Cordis 对外服务接口与事件契约建立不可豁免的 JSDoc 完整性门禁让每个导出都有解释语义的 JSDoc这类写作规则从靠评审人肉检查升级为目录生成器 CI 自动拒绝。读完你将掌握门禁覆盖的精确范围哪些事件、哪些服务方法必须写文档、每条守卫的具体判定规则与免检例外this接收者、waterfall 的next、void返回值、它为什么放在生成器而非 ESLint 规则里以及如何在本地复现verify-cordis-catalog检查。问题背景IDE 引导最重要的地方文档却可以缺席Cordis 是 DeepSeek Harness 的插件运行时Everything is a Plugin 的架构使得ctx.key服务与Events事件成为跨插件协作的公共接口。此前生成的 Cordis 目录只强制了事件分发模式mode标签却未强制要求完整的服务与事件契约方法可以完全没有描述文字参数或返回值可以在跨插件 API 接口上不写文档而这些恰恰是 IDE 悬停提示、Agent 阅读源码时引导最重要的地方。仓库根目录 AGENTS.md 中的通用写作规则「每个导出都有解释语义的 JSDoc」只能靠评审以行文形式检查而本仓库的既定偏好是把不变式编码为机械门禁——这正是本次决策的出发点。核心决策为什么门禁必须放在目录生成器里「Cordis 服务函数与事件」这一范围有精确的机器定义而只有目录生成器知道它事件是declare module cordis内interface Events的成员服务接口是每个interface Context键所指向的类的公开方法ESLint 规则看不到这层映射——它无法知道哪些interface Events成员、哪些ctx.key类构成 Cordis 对外服务接口生成器在每次运行时恰好计算出这层映射因此门禁被放置在 scripts/gen-cordis-catalog.ts它复用同一次遍历和同一套mode先例对所有编目内容强制执行 JSDoc 完整性要求。从 package.json 可以看到配套的命令接线# 生成默认会先执行全部门禁检查任何违规都会中止 pnpm run gen-cordis-catalog # 校验模式验证已提交的生成产物是否新鲜 pnpm run verify-cordis-catalog其中verify-cordis-catalog即tsx scripts/gen-cordis-catalog.ts --check被挂入 scripts/run-gates.ts 的doc-sync门禁组因此相关文档变更和 CI 会执行同一道门禁无需另行接线。门禁契约四条守卫与两类免检事件描述文字 每个载荷参数的非空param每个事件需要描述性文字JSDoc 正文位于块标签之上解释发生了什么、监听者可以做什么为每个载荷参数提供非空的param。载荷参数是携带事件数据的签名参数以下两类免检this接收者注解属于签名机制而非数据载荷尾部的 waterfallnext它是分发机制其语义已由mode waterfall标签及其结构交叉检查拥有逐事件重述只是样板代码。值得注意的有意不对称为免检参数写文档是允许的只有缺失才被检查——门禁强制载荷契约但拒绝要求样板代码。在 packages/typert/generator/src/cordis-catalog.ts 的collectEvents实现中可以看到完整判定mode缺失、描述文字为空、param缺失都会触发违规checkParams会以parameter parameter.receiver || (hasNext parameter last)作为免检谓词恰好对应this与尾参next。服务类类级 JSDoc 每方法的param/returns服务类需要类级 JSDoc类名ctx.key指向的类或接口必须有说明文字每个公开方法需要描述性文字每个参数提供非空的param非空的returns——除非标注的返回类型是void/Promisevoid此时returns可选resolve 时机有时值得记录但从不强制要求。checkReturns见 cordis-catalog.ts的实现与此完全一致它通过渲染器解析返回类型type void || type Promisevoid时直接放行否则要求returns存在且描述非空。陈旧标签报错param必须命中真实参数param命名了一个不存在的参数即为违规这与mode与签名矛盾的检查对称cordis-catalog.ts。标签描述必须非空超出此范围的语义质量描述是否准确、是否传达意图由评审负责。遍历可检查的显式性纯 AST不用类型检查器门禁是纯 AST 遍历不使用类型检查器因此带来两条硬性约束服务方法必须显式标注返回类型——推断的返回类型无法被分类也就无法判定是否需要returns接口参数必须是简单标识符——解构模式没有名称可供param匹配。从源码结构看这两条约束在采纳时均未构成限制所有方法已有标注、不存在解构的 seam 参数但它们现在是承重要求违反时会被机械检测到checkParams 会对 binding pattern 参数直接报错。聚合错误报告一次看到完整清单所有违规被聚合为一条错误信息列出全部违规项——修复时一次看到完整清单而不是被快速失败逐个打断。此前快速失败的mode检查也被移入同一份聚合报告消息文本不变见 reportViolations所有collectEvents/collectServices收集到的违规统一在此抛出。这种设计对以绿色状态落地至关重要采纳本门禁时发现的约139 处缺口在同一变更中全部补齐生成器拒绝重新生成、CI 拒绝合并直到清单清零。两种视图并存可扫读的正文 完整的源码契约生成器保留同一源码注释的两种视图cordis-catalog.ts 的parseJsDoc正文摘要parseJsDoc在第一个块标签param/returns/mode等处结束条目正文因此可读索引区只含描述文字块标签文本不会泄漏进周围正文签名块ts cordis-catalog围栏包含原始 JSDoc完整保留param、returns和mode。读者因此既能看到干净的概览正文又能在签名旁看到确切契约同时源码编辑会同时刷新可读索引和签名旁展示的精确契约——文档与源码之间不存在第二个手写副本。负路径测试每条守卫都有合成 fixture 验证门禁的每条判定都有对应的负路径测试即违规必须触发的测试运行于合成 fixture 之上覆盖事件缺mode、mode与尾参next矛盾、mode waterfall却无next缺param、陈旧param、空描述param、解构参数服务方法缺param、缺returns、缺类级 JSDoc、推断返回类型免检规则成立this接收者与 waterfallnext不需要paramvoid方法不需要returns。这些测试集中在 packages/typert/generator/tests/cordis-catalog-contract.spec.tscollectEvents/collectServices的契约级测试并配合 packages/typert/generator/tests/cordis-catalog.spec.ts 验证真实工作区投影与页面渲染。此外scripts/gen-cordis-catalog-partition.spec.ts 与 scripts/gen-cordis-catalog-record.spec.ts 分别守护分区映射与记录级产物。曾考虑的替代方案为什么是生成器而不是 ESLint方案结论与理由ESLint 规则否决。ESLint 无法看到该范围的机器定义哪些interface Events成员、哪些ctx.key类构成 Cordis 对外服务接口目录生成器在每次运行时恰好计算这层映射因此门禁放在生成器里。将每个方法展开为单独的正文小节否决。目录保留一个服务章节和一个签名块以维持可扫读性附着于每个声明的 JSDoc 则在原处保留完整的方法契约。逃逸标签豁免开关不设。该接口面小且经过策展——采纳时约12 个服务、57 个方法、27 个事件——要点在于检查不可豁免。配套的失败封闭分区服务与事件不可能静默消失门禁之外生成器还维护一套双向失败的封闭分区walkPartitionProblems每个被渲染的ctx.key服务、每个事件 scope 都必须映射到恰好一个docs/subsystems/页面见 SERVICE_PAGE 与 EVENT_SCOPE_PAGE映射表中的条目若不再被发现报删除陈旧条目独立的 AST 扫描读取每一个declare module deepseek-ai/cordis的 Context/Events merge任意深度渲染投影不可见的新键必须显式列入 SERVICE_WALK_EXEMPTIONS 或 EVENT_WALK_EXEMPTIONS 并注明文档所有者launcher 提供的引导值、client 端浏览器面服务、客户端事件等类别反向自检被渲染的键/事件若扫描不可见说明扫描自身退化了glob、prefilter 或模块块遍历必须修扫描而非改映射表。这一层确保JSDoc 完整性门禁不是孤岛一个新服务或新事件要么进目录接受文档检查要么显式登记豁免永远不可能静默漏检。后果与工程权衡新事件或服务方法不能带着未记录的参数或结果落地生成器拒绝重新生成verify-cordis-catalog使doc-sync和 CI 失败服务接口必须显式标注返回类型并使用标识符参数两项约束在采纳时未构成限制但现在是承重要求AGENTS.md 通用 JSDoc 规则在此接口上获得更严格的特例仅当方法无参数且返回void时一行摘要才足够通用规则是一行能说清就用一行为next或this写param合法但不检查这是有意的不对称——门禁强制载荷契约拒绝要求样板代码每个生成的事件或方法片段都携带原始 JSDoc正文摘要不含标签源码编辑会同时刷新可读索引与签名旁的确切契约。在本地复现与运用这套门禁# 1. 校验已提交的生成产物包含全部 JSDoc 完整性检查 pnpm run verify-cordis-catalog # 2. 修改了某个服务的公开方法或事件签名后重新生成目录 pnpm run gen-cordis-catalog # 3. 作为 doc-sync 门禁组的一部分随 CI 执行 pnpm run doc-sync实践建议当你在 Harness 的某个packages/*/*/src/**下新增ctx.key服务方法、事件或interface Context/interface Eventsmerge 时遵循以下清单即可一次通过给类/接口写类级 JSDoc给事件写描述正文每个参数写param name - 描述描述非空this与 waterfall 尾参next可免非void/Promisevoid的方法写returns使用简单标识符参数不要用解构模式显式标注返回类型新服务/事件若渲染投影不可见在 gen-cordis-catalog.ts 的豁免表登记并注明文档所有者运行pnpm run gen-cordis-catalog重新生成确认无聚合违规后再提交。这套门禁的完整实现集中在 scripts/gen-cordis-catalog.ts驱动器、分区映射、策略常量与 packages/typert/generator/src/cordis-catalog.ts投影器、parseJsDoc、各条守卫测试则见 packages/typert/generator/tests/cordis-catalog-contract.spec.ts。对于想要在自有插件架构中复制写作规则机械化模式的团队本实现提供了一个可参考的范本把只有特定组件才掌握的精确范围定义与纯 AST、可测试、聚合报错的门禁逻辑放在同一处并用双向失败封闭的分区表堵住所有静默逃逸路径。【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考