# 众测任务创建表单内容 --- ## ① 众测框架选择 **选择:云端 Claude Code** --- ## ② 任务标题 ``` 调度网关 P0 生产化基线加固(状态机/Repository/幂等/取消/死信/回调/事件/健康检查/测试,共11项任务) ``` --- ## ③ 首轮 Prompt ``` 你正在参与 scheduler-gateway-epoch 6.0.0 的第一阶段 P0 生产化基线开发。 ## 项目背景 这是一个 DSH 调度网关:中心网关 + 任务队列 + 节点协议(gw-node/1)+ 真实 LLM 多智能体编排(planner→workers→reviewer→merger)。当前是可演示、可验收的单机原型,需要工程化加固为可长期运行、可恢复、可审计的执行平台。 项目特点:Node.js >= 20,原生 ESM,零第三方运行时依赖。 ## 必读文件 开工前必须先阅读以下文件,确认现有行为后再修改: - README.md — 项目总览与快速开始 - ARCHITECTURE.md — 架构与协议 - IMPLEMENTATION.md — 实现细节与验证方式 - ADR.md — 关键决策记录 - PHASE-1-UNIFIED-TASK.md — 完整任务书(你的主要参考) - src/server.js — HTTP 网关、节点协议、任务 API - src/store.js — 任务/节点/审计/事件存储 - src/scheduler-core.js — 调度、领取、结算、重试、死信 - src/protocol.js — 状态常量、节点协议、鉴权 - src/wal.js — JSONL WAL ## 技术约束(必须遵守) 1. Node.js >= 20,原生 ESM,零第三方运行时依赖 2. 保持现有 API 兼容,不破坏既有接口语义 3. 保持 REAL/OFFLINE/fixture 诚实标记 4. 不得泄漏任何密钥(key/token/password/secret) 5. 不得修改 归档-*、out、work、evidence 中已有历史产物 6. 不得通过任意 task.state = ... 绕过状态机 7. 不得通过放宽断言、增加无限重试、忽略异常来制造全绿 8. 新增模块优先放在 src/domain、src/application、src/adapters、src/platform 9. 先包裹旧实现,再逐步迁移调用方;不要一次性重写 server.js 或 orchestrate.js ## 需要完成的 11 个任务 ### 任务 A:任务状态机 新增 src/domain/task-state-machine.js: - 定义当前任务所有合法状态和迁移(queued/running/done/succeeded/failed/dead/rework/waiting_approval/canceled) - 提供 canTransition(from, to)、transition(task, to, context) 等接口 - 迁移失败抛出稳定错误码 INVALID_STATE_TRANSITION - 迁移时追加历史记录(操作者/原因/时间/attemptId/requestId) - 将 server.js、store.js、scheduler-core.js 中直接修改状态的关键路径迁移到状态机 - 重复 settle、过期 lease settle、已取消任务回报等场景必须拒绝或转为幂等成功 ### 任务 B:Repository 抽象 新增 src/domain/repositories.js + src/adapters/storage/file-repository.js: - 至少抽象任务、节点、事件、审计、死信和产物索引访问 - 现有 GatewayStore 可作为兼容实现,但业务服务不得继续依赖 Map 的内部结构 - 保留 persist:false 的干净内存测试模式 - 保留现有 JSON 落盘和 WAL 能力 - Repository 方法必须区分"找不到""冲突""非法状态""存储失败" - 为未来 SQLite/PostgreSQL 实现保留异步接口 ### 任务 C:幂等键和租约 - 创建任务支持 Idempotency-Key;重复请求返回同一任务 - claim 生成唯一 leaseId,记录 leaseExpiresAt、nodeId、attemptNo - settle 必须校验 lease;重复提交同一 leaseId + 相同结果幂等返回;不同结果拒绝并审计 - lease 过期后任务可重投,但旧节点迟到回报不得覆盖新结果 - retry、cancel、approve、amend 具备幂等行为 - 不得用进程内 Map 作为唯一幂等数据来源 ### 任务 D:统一错误、审计和请求关联 - 新增稳定错误码集合(INVALID_ARGUMENT / TASK_NOT_FOUND / INVALID_STATE_TRANSITION / LEASE_NOT_FOUND / LEASE_EXPIRED / IDEMPOTENCY_CONFLICT / TASK_ALREADY_TERMINAL / STORAGE_ERROR / REVISION_CONFLICT) - 每个 HTTP 请求生成或透传 X-Request-Id - 每个任务运行生成或透传 runId、taskId、attemptId、nodeId - 审计记录至少包含:时间、动作、对象、结果、操作者/来源、requestId、runId、错误码 - API 错误统一为 { error: { code, message, requestId, details } } - 保持现有接口状态码兼容 ### 任务 E:健康检查和配置校验 新增 src/platform/config.js + src/platform/health.js: - 统一读取端口、host、数据目录、WAL、节点 token、TLS、LLM provider 和超时配置 - 新增 gateway check 或等价检查命令 - 新增 /healthz(进程存活)和 /readyz(数据目录/WAL/Repository 可写性、必要配置) - 生产模式检测到默认节点 token 时必须给出明确警告;安全模式可直接拒绝启动 - 检查结果必须脱敏 ### 任务 F:补齐测试和验证脚本 新增或扩展测试: - 状态机:合法迁移、非法迁移、重复终态、取消竞态 - Repository:内存态、文件态、WAL 开关、损坏文件、恢复后读取 - 幂等:重复创建、重复 claim、重复 settle、冲突 settle、过期 lease - 故障:进程中断、节点掉线、旧节点迟到回报、回调失败、磁盘不可写 - 安全:错误响应不泄漏密钥,requestId 和审计不泄漏敏感字段 - 回归:现有 npm test、npm run test:conversation、npm run e2e-team 能继续运行 ### 任务 G:任务版本与乐观锁 - 每个任务带 revision(整数,初始 1),每次 transition/settle/update 成功后自增 - transitionTask、settleTask、updateTask 必须接受 expectedRevision;不匹配返回 REVISION_CONFLICT - 重复提交相同 leaseId + 相同结果时,revision 不变,幂等返回当前终态 - 不同结果或不同 attemptId 的 settle 必须因 revision/lease 校验失败而拒绝 - revision 必须随任务持久化,重启后恢复 - 审计记录每次 revision 变化 ### 任务 H:事件持久化与 SSE 重连 - 事件通过 EventRepository 持久化(FileRepository 先落 JSONL) - 每个事件带 seq(全局递增)、type、aggregateId、revision、at、requestId - SSE 支持 Last-Event-ID:客户端断线重连时从 Last-Event-ID + 1 开始补播 - 事件保留期可配置(默认 7 天或 10000 条) - 进程重启后 seq 必须继续递增,不能回退 ### 任务 I:回调机制加固 - 回调必须有 HMAC-SHA256 签名:X-Signature: t=,v1= - 回调失败按指数退避重试(至少 3 次:1s / 5s / 30s);全部失败后进入回调死信队列 - 回调必须幂等:接收方可用 X-Callback-Id(= taskId)去重 - 回调 payload 必须包含 taskId、runId、state、revision、result、finishedAt - 密钥不得出现在日志、审计、导出或错误消息中 ### 任务 J:任务取消传播 - cancel 必须将取消信号传播到持有当前 lease 的执行节点 - 取消后任务进入 canceled 终态;执行节点的迟到回报在任务已 canceled 时必须被拒绝 - 如果任务有子任务(parentRun / dependencies),取消父任务时必须级联取消未完成的子任务 - 取消操作本身必须幂等:对已 canceled 的任务再次 cancel 不报错 - 取消必须审计:记录谁取消、为什么取消、取消传播到了哪些子任务 - 如果节点不在线或取消信号投递失败,任务仍应进入 canceled 终态(取消不依赖节点确认) ### 任务 K:死信队列加固 - 每条死信记录必须包含:deadLetterId、taskId、originalTaskId、deadReason、retryCount、firstDeadAt、lastDeadAt - 死信重投有上限:maxDeadRetries(默认 3);超过后标记 exhausted - exhausted 死信只能通过人工 POST /api/deadletter/:id/force-retry 重投,且必须记录操作者 - 死信队列支持按 deadReason / retryCount / originalTaskId 查询 - 死信重投必须生成新的 attemptId 和 leaseId,不能复用旧 lease - 死信归档:exhausted 超过保留期后自动归档 ## 验收标准 ### 功能验收 - [ ] 所有关键状态迁移经过统一状态机 - [ ] 业务层不再直接依赖 GatewayStore 的内部 Map 结构 - [ ] create/claim/settle/retry/cancel/approve 支持幂等或冲突检测 - [ ] 任务拥有 leaseId、leaseExpiresAt、attemptId 等执行关联字段 - [ ] 旧 lease 的迟到回报不能覆盖新 attempt - [ ] /healthz、/readyz 和配置检查可用 - [ ] 错误响应包含稳定错误码和 requestId - [ ] 审计能够还原一次任务从创建到终态的完整过程 - [ ] 任务带 revision,并发 settle 只有一个成功,REVISION_CONFLICT 正确返回 - [ ] 事件持久化到 Repository,SSE 断线重连后能补播断线期间的事件 - [ ] 回调有 HMAC 签名、失败重试 3 次、全部失败进死信队列 - [ ] 取消信号传播到执行节点,已取消任务的迟到回报被拒绝,子任务级联取消 - [ ] 死信带 retryCount/originalTaskId/deadReason,超过 maxDeadRetries 标记 exhausted ### 回归验收 所有命令退出码为 0: npm test npm run test:conversation npm run e2e-team npm run recovery-demo npm run stress ### 性能验收 - 在现有压测规模下,任务无重复领取、无永久丢失、无重复终态 - 新增状态机、Repository、审计后,现有 stress 测试吞吐下降不超过 10% - 必须提供改造前后的 baseline 对比数据:吞吐(task/s)、P95/P99 排队延迟、P95/P99 执行延迟、重复领取数、丢失任务数 - 事件持久化不能阻塞调度主路径 ### 安全验收 - 错误、审计、状态、导出、日志中均不存在 key/token/password/secret 明文 - 默认 token、非法路径、非法状态、伪造 lease、越权 settle 均有拒绝结果 - 不引入新的 shell 拼接、动态代码执行或不受限文件路径 ## 交付物格式 每个模型必须提交以下内容: 1. 修改文件清单 2. 实现摘要 3. 状态迁移表 4. Repository 接口说明 5. 幂等和 lease 语义说明 6. 测试命令与实际结果 7. 未完成项和已知风险 8. 与其它模型合并时的冲突点 禁止只提交"已完成""测试通过"等无证据结论。 ## 执行步骤建议 1. 先读 README.md、ARCHITECTURE.md、IMPLEMENTATION.md、ADR.md、PHASE-1-UNIFIED-TASK.md 2. 读 src/server.js、src/store.js、src/scheduler-core.js、src/protocol.js、src/wal.js,理解现有任务生命周期 3. 按以下顺序实现:状态机(A) → 错误码(D) → 版本乐观锁(G) → Repository(B) → 事件持久化(H) → 幂等lease(C) → 取消传播(J) → 回调加固(I) → 死信加固(K) → 健康检查(E) → 测试(F) 4. 每完成一个任务,运行 npm test 确认没有回归 5. 全部完成后运行回归验收的 5 条命令,记录实际退出码 6. 按交付物格式提交结果 注意:你是四个并行模型之一,使用完全相同的任务书。你的目标是提交可合并代码。保持 Node >=20、零第三方运行时依赖、REAL/OFFLINE 诚实标记和现有 API 兼容。不得修改归档目录,不得删除用户已有改动,不得泄漏任何密钥。完成后必须运行对应测试,报告实际命令、退出码、修改文件和剩余风险。 ``` --- ## ④ Rubrics 描述 ``` ## 评估维度与判定标准 ### 1. 功能完整性(权重 30%) 优秀: - 11 个任务(A-K)全部实现并接入真实任务路径 - 所有功能验收项(13 项)全部通过 - 状态机覆盖所有合法/非法迁移,重复终态和取消竞态正确处理 - Repository 抽象完整,业务层不再依赖 Map 内部结构 - 幂等和 lease 在并发、重复、过期场景下行为正确 - 事件持久化 + SSE 重连正常工作 - 回调有签名、重试、死信 - 取消传播到节点和子任务 - 死信有 retryCount/上限/归档 合格: - 核心任务(A/B/C/D)完成,其余任务部分完成 - 主要功能验收项通过,少数边缘场景未覆盖 - 代码可运行,测试大部分通过 不合格: - 关键任务(状态机/Repository/幂等)未实现或未接入 - 功能验收项超过 3 项不通过 - 代码无法运行或测试大面积失败 ### 2. 代码质量(权重 20%) 优秀: - 新增模块结构清晰(domain/application/adapters/platform 分层) - 函数职责单一,命名清晰,注释充分 - 错误处理完善,不吞异常 - 与现有代码风格一致(ESM、零依赖) - 没有死代码、重复代码或过度工程 合格: - 模块结构基本合理,有少量设计瑕疵 - 命名和注释基本到位 - 错误处理覆盖主要路径 不合格: - 模块结构混乱,职责不清 - 大量复制粘贴或死代码 - 异常被静默吞掉 - 引入了第三方运行时依赖 ### 3. 测试覆盖(权重 20%) 优秀: - 每个新增功能都有对应测试 - 测试覆盖正常路径、边界条件、错误场景 - 并发和竞态场景有专门测试 - 现有测试全部通过(npm test 等) - 新增测试覆盖状态机、Repository、幂等、lease、取消传播、死信加固、事件持久化 合格: - 主要功能有测试覆盖 - 现有测试基本通过(允许少量已知 flaky) - 边界场景覆盖不完整但有计划 不合格: - 没有新增测试 - 现有测试被破坏 - 通过放宽断言或删除测试来制造全绿 ### 4. 兼容性(权重 15%) 优秀: - 现有 API 完全兼容,不改变接口语义 - 现有测试(npm test / test:conversation / e2e-team / recovery-demo / stress)全部通过 - 现有面板、插件、看板桥和团队编排功能未被破坏 - WAL 和持久化行为保持兼容 合格: - 现有 API 基本兼容,有少量非破坏性变化 - 现有测试大部分通过 不合格: - 破坏现有 API 语义 - 现有测试大面积失败 - 面板、插件或团队编排功能被破坏 ### 5. 安全性(权重 15%) 优秀: - 错误、审计、状态、导出、日志中均不存在 key/token/password/secret 明文 - 默认 token 检测和警告到位 - 非法路径、非法状态、伪造 lease、越权 settle 均有拒绝结果 - 回调签名(HMAC)正确实现 - 不引入新的 shell 拼接、动态代码执行或不受限文件路径 合格: - 主要安全检查到位 - 密钥脱敏基本覆盖 - 个别安全场景未覆盖但有计划 不合格: - 密钥泄漏到日志/审计/导出 - 默认 token 在生产模式下不警告 - 缺少基本的安全校验 ### 综合判定 - 优秀:5 个维度均为优秀或合格,且至少 3 个为优秀 - 合格:5 个维度均为合格及以上,且不超过 2 个为不合格 - 不合格:任意 2 个及以上维度为不合格 ``` --- ## ⑤ 上传附件(Workspace)说明 ### 必须上传的文件/目录 ``` src/ 所有源码(含 src/nodes/、src/taskboard/、src/team/) test/ 所有测试(含 test/fixtures/) web/ Web 面板 scripts/ 工具脚本 lib/ DSH 插件封装 package.json README.md ARCHITECTURE.md IMPLEMENTATION.md ADR.md PHASE-1-UNIFIED-TASK.md DEVELOPMENT-ROADMAP.md cordis.patch.yml .env.example .gitignore gateway POSIX 启动器 gateway.cmd Windows 启动器 ``` ### 不要上传的 ``` node_modules/ 零依赖项目不需要 out/ 运行产物,可重新生成 evidence/ 运行证据,可重新生成 work/ 工作目录,可重新生成 state/ 运行时状态 归档-* 归档目录,任务不需要 .env.live 含 API 密钥,禁止上传! _*.mjs / _*.js / _*.html / _*.txt 临时脚本 *.docx / *.png 大二进制文件 _merge_work/ 合并工作目录 ``` ### 打包建议 把项目根目录下需要上传的文件/文件夹打成一个 zip,保持原始目录结构: ```bash # 在项目根目录执行 zip -r workspace.zip src/ test/ web/ scripts/ lib/ \ package.json README.md ARCHITECTURE.md IMPLEMENTATION.md \ ADR.md PHASE-1-UNIFIED-TASK.md DEVELOPMENT-ROADMAP.md \ cordis.patch.yml .env.example .gitignore gateway gateway.cmd ``` 然后上传 workspace.zip 作为 Workspace。