@twinsearth/dsh-master 0.0.0-stage → 3.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +89 -2
  3. package/client.js +263 -0
  4. package/cordis.patch.yml +71 -0
  5. package/dist-host/contract/client.js +82 -0
  6. package/dist-host/contract/constants.js +70 -0
  7. package/dist-host/contract/envelope.js +84 -0
  8. package/dist-host/contract/index.js +17 -0
  9. package/dist-host/contract/negotiate.js +87 -0
  10. package/dist-host/contract/server.js +71 -0
  11. package/dist-host/contract/transports.js +360 -0
  12. package/dist-host/index.js +260 -0
  13. package/dist-host/kernel.js +186 -0
  14. package/dist-host/plugins/cost-optimizer.js +147 -0
  15. package/dist-host/plugins/dual-manager.js +251 -0
  16. package/dist-host/plugins/superagent-router.js +499 -0
  17. package/dist-host/plugins/superagent-worker.js +73 -0
  18. package/dist-host/superagent/bridge-tokens.js +236 -0
  19. package/dist-host/superagent/dispatch.js +198 -0
  20. package/dist-host/superagent/feishu.js +115 -0
  21. package/dist-host/superagent/github.js +119 -0
  22. package/dist-host/superagent/pr-delivery.js +351 -0
  23. package/dist-host/superagent/router.js +219 -0
  24. package/dist-host/superagent/stream-adapter.js +238 -0
  25. package/dist-host/superagent/stream-tokens.js +141 -0
  26. package/dist-host/superagent/ticket-store.js +108 -0
  27. package/dist-host/superagent/trust.js +145 -0
  28. package/dist-host/superagent/types.js +144 -0
  29. package/dist-host/superagent/worker.js +95 -0
  30. package/dist-host/superagent/writeback.js +162 -0
  31. package/dist-worker/agent-loop.js +493 -0
  32. package/dist-worker/errors.js +41 -0
  33. package/dist-worker/github-pr.js +44 -0
  34. package/dist-worker/index.js +323 -0
  35. package/dist-worker/llm-http.js +351 -0
  36. package/dist-worker/main.js +45 -0
  37. package/dist-worker/prompt.js +35 -0
  38. package/dist-worker/sink-http.js +135 -0
  39. package/dist-worker/tools.js +542 -0
  40. package/dist-worker/types.js +14 -0
  41. package/docs/ARCHITECTURE.md +114 -0
  42. package/docs/CHANGELOG.md +377 -0
  43. package/docs/INTEROP.md +60 -0
  44. package/docs/REVIEW-v3.2.7.md +121 -0
  45. package/docs/ROADMAP.md +106 -0
  46. package/docs/SECURITY.md +153 -0
  47. package/docs/SMOKE-3.2.5.md +77 -0
  48. package/docs/SMOKE-3.2.7.md +73 -0
  49. package/docs/SUPERAGENT.md +141 -0
  50. package/docs/WORKER-AGENT-LOOP.md +139 -0
  51. package/icon.svg +9 -0
  52. package/locale/en.json +6 -0
  53. package/locale/zh.json +6 -0
  54. package/package.json +79 -4
  55. package/src/contract/client.js +86 -0
  56. package/src/contract/constants.js +79 -0
  57. package/src/contract/envelope.js +83 -0
  58. package/src/contract/index.js +19 -0
  59. package/src/contract/negotiate.js +106 -0
  60. package/src/contract/server.js +77 -0
  61. package/src/contract/transports.js +319 -0
  62. package/src/index.ts +265 -0
  63. package/src/kernel.ts +190 -0
  64. package/src/plugins/cost-optimizer.ts +155 -0
  65. package/src/plugins/dual-manager.ts +252 -0
  66. package/src/plugins/superagent-router.ts +465 -0
  67. package/src/plugins/superagent-worker.ts +85 -0
  68. package/src/superagent/bridge-tokens.ts +236 -0
  69. package/src/superagent/dispatch.ts +197 -0
  70. package/src/superagent/feishu.ts +104 -0
  71. package/src/superagent/github.ts +111 -0
  72. package/src/superagent/pr-delivery.ts +308 -0
  73. package/src/superagent/router.ts +201 -0
  74. package/src/superagent/stream-adapter.ts +184 -0
  75. package/src/superagent/stream-tokens.ts +142 -0
  76. package/src/superagent/ticket-store.ts +104 -0
  77. package/src/superagent/trust.ts +139 -0
  78. package/src/superagent/types.ts +135 -0
  79. package/src/superagent/worker.ts +100 -0
  80. package/src/superagent/writeback.ts +154 -0
  81. package/tsconfig.host.build.json +12 -0
  82. package/tsconfig.host.json +21 -0
  83. package/tsconfig.worker.build.json +13 -0
  84. package/tsconfig.worker.json +17 -0
  85. package/types/superagent.d.ts +99 -0
  86. package/worker/agent-loop.ts +524 -0
  87. package/worker/errors.ts +47 -0
  88. package/worker/github-pr.ts +65 -0
  89. package/worker/index.ts +334 -0
  90. package/worker/llm-http.ts +359 -0
  91. package/worker/main.ts +45 -0
  92. package/worker/prompt.ts +39 -0
  93. package/worker/sink-http.ts +159 -0
  94. package/worker/tools.ts +531 -0
  95. package/worker/types.ts +247 -0
@@ -0,0 +1,377 @@
1
+ ## 3.2.8(2026-11-12,tag / GitHub Release / NPM public)
2
+
3
+ **主题:真实双 Host/fork 验收驱动的安全、生命周期、契约与 UI 收口。**
4
+
5
+ - Worker:prompt 工具名对齐真实 registry;周期死循环遵守 `maxIdenticalToolRepeats`;sink 请求超时与有界 close;Shell 结算/中止修复;>5s 后台 job + `vm_job_result`;完成后记录真实 token 到 HarnessMM observe。
6
+ - Router:dispatch 异常落 failed 并释放配额/撤销 token;watchdog 覆盖 pending 且参考事件活动时间;`GET /superagent/session` 落地;worker-events GET 需要 UI 或匹配 worker token;token 轮换拒绝未知旧 token;同一路径 GET/POST 合并 handler(DSH 按 kind+path 去重)。
7
+ - 契约:idempotencyKey 进入 local/http/file envelope;per-call timeout 生效;文件传输真实响应/超时测试;成功响应后清理由调用方负责,并对 Windows 句柄竞争有界重试;dispatch status 暴露 attempts。
8
+ - PR:`create()`/`pushFile()` 同样执行分支与路径护栏;全部 GitHub fetch 加超时;`deliver()` 幂等与受保护分支/路径/体积断言;WorkerResult 可携带 pr 元数据,Router 有 files 时走 `deliver()`。
9
+ - 事件与 UI:飞书 Encrypt Key AES-256-CBC 解密;LiveFeed 轮换携带当前 token、卸载清理、完成后不再显示“工具中”。
10
+ - PJM:spawn 改用 `homeDir/cliPath/profile/taskTitle/env` 契约,dispatch 单飞防重复派生。
11
+ - 测试与文档:185/185 通过;`test:clean` 不使用 `--test-force-exit` 同样全绿;清理 138 个历史临时目录,最终测试残留为空;修复过期版本与限制说明,新增 `REVIEW-v3.2.7.md`、`SMOKE-3.2.7.md`。
12
+
13
+ ## 3.2.7(2026-11-12)
14
+
15
+ **主题:Webhook 立即 202(异步派发)+ PR 自动交付(宿主推送分支)。**
16
+
17
+ ### 修复
18
+ - **Webhook 阻塞 60s**:此前 GitHub/飞书 Webhook 处理器同步等待 `dispatcher.dispatch()`,
19
+ 而 fork 预置需 10–30s、整条工单可达 60s,远超 GitHub 的 ~10s 超时(会触发重投与重复工单)。
20
+ 现在 `ingest(event, { defer: true })` 先落库存票并 **立即返回 202**,派发在后台执行;
21
+ 后台失败仍会落 `failed(dispatch-async-failed)`,状态接口可查。
22
+
23
+ ### 新增(PR 自动交付)
24
+ - `pr-delivery.deliver()`:**宿主侧**建分支 → 逐文件提交 → 开 PR(Worker 全程无 push 凭据);
25
+ `branchForTicket()` 命名策略 `superagent/<source>-<ticket>-<hash8>`(幂等:同票同分支);
26
+ 幂等 PR:已存在 open PR 直接复用,不重复开单;
27
+ 路径白名单:拒绝绝对路径、`..`、`.git/`、`.github/workflows/`;上限 30 文件 / 2MB;
28
+ 受保护分支(main/master/trunk/release/production/stable/develop)不可作 head 或 base。
29
+ ## 3.2.6(2026-11-11)
30
+
31
+ **主题:审计闭环(P1-3 全步脱敏、P2 四项、派发超时适配 fork 预置)+ 测试缺口补齐。**
32
+
33
+ ### 安全
34
+ - **P1-3 步骤统一脱敏**:`record()` 对所有步骤内容脱敏(含 `error`/`thought`/`final_answer`),
35
+ 修掉异常消息里带凭据绕过单点脱敏的缺口;新增 2 条回归测试。
36
+ - **P2 四项**:`.env*` 全形态写保护;死循环改“规格连续判定 + 滑动窗口补充(阈值 2×)+ 工具总调用硬顶”;
37
+ `create_pr` branch/base 白名单校验;`limits` 绝对上限已在 v3.2.5 冻结。
38
+
39
+ ### 修复
40
+ - **派发超时适配 fork 预置**:契约传输超时默认 10–15s,而母体 `fork.spawn` 的预置常需 10–30s,
41
+ 导致「母体已成功派生、房主却记失败」并可能重复派发。现默认 180s,可用
42
+ `dispatch.contractTimeoutMs` / `dispatch.contractFileTimeoutMs` 覆盖。
43
+
44
+ ### 测试
45
+ - 新增审计闭环用例:子进程环境实证、8 种 Shell 逃逸、超大单条响应、A/B 交替死循环、
46
+ 工具总调用上限、`.env` 全形态、PR 参数校验、规格连续判定(3 次允许 / 第 4 次拒绝 / 换参不误杀)。
47
+ - 全量 **154/154 通过**;`docs/SECURITY.md` 增加「审计项 → 测试名」对照表(12 行)。
48
+ ## 3.2.5(2026-11-11,开发中)
49
+
50
+ ### 零配置派发桥(配合瓮城 3.1.16)
51
+ - `dispatch.ts` 在 `DSH_FANG_MOTHER` 存在且未显式配置 `contractFileDir` 时,自动使用
52
+ `<DSH_FANG_MOTHER>/contract-outbox` 作为契约 file 桥目录;
53
+ - 瓮城 3.1.16 已把该环境变量注入原身运行态,原身 Router → 母体契约 → 真实 fork 的链路免配置;
54
+ - HTTP 桥需要 `motherUrl + motherToken + motherAuthToken`(契约 Bearer + 安装级 x-fang-auth)。
55
+
56
+ ### P2 纵深加固(敏感路径 / 死循环 / PR 参数)
57
+ - **敏感路径写保护**:`.env` 的**所有变体**(`.env`、`.env.local`、`.env.production`、`.env.example`…)
58
+ 一律拒绝写入(此前只枚举了 `.env`/`.env.local`);`.git`/`.dsh`/`.ssh`/`node_modules/.cache` 保持拒绝;
59
+ - **死循环检测改为滑动窗口**:最近 40 次调用的窗口内同签名(工具名+参数)出现次数 > `maxIdenticalToolRepeats`
60
+ 即判 `dead-loop-detected`——`A/B/A/B` 交替调用不再能绕过(此前只判“连续相同”);
61
+ - **工具调用总量上限**:`maxSteps × maxToolCallsPerStep`(硬顶 1000)→ 超出报 `tool-call-budget-exceeded`,
62
+ 覆盖“每次参数都不同”的失控循环;
63
+ - **create_pr 参数校验**:必须显式 `branch`;拒绝非法分支名(`..`、前导 `-`、`//`、非法字符);
64
+ 拒绝把受保护分支(main/master/trunk/release/production/stable)作为 head;
65
+ `base` 必须是受保护主干;`branch` 不得等于 `base`;
66
+ - 测试新增 4 例(A/B 交替死循环、总调用上限、.env 全形态、PR 参数),全量 **149/149 通过**。
67
+
68
+ ### P1 纵深加固(Mandate / 预算 / 脱敏)
69
+ - **Mandate 一致性**:Ticket 的 `mandate.scope` 必须与 Worker 构造时授权一致,否则 `mandate-mismatch` 直接失败;
70
+ `allowShell` **取交集**(Ticket 只能收窄、不能放宽);新增测试证明“Ticket 想把 allowShell 放宽为 true 也会被压回 false”;
71
+ - **预算兜底**:provider 不返回 `usage` 时按 `序列化长度 / 4` 估算,估算后立即参与 `maxTokens` 判定,
72
+ 避免“不返回 usage 就能绕过预算”;另受 `maxContextChars`(上下文)与单条响应长度双重上限;
73
+ - **脱敏**:`redactSecrets()` 覆盖 `sk-*` / `github_pat_*` / `gh[pousr]_*` / `AKIA*` / `Bearer *` / 私钥块;
74
+ `secretValuesOf()` 由“白名单两项”扩展为**凭据形态全收**(`*_API_KEY/_APIKEY/_TOKEN/_SECRET/_PASSWORD` 且长度 ≥ 8),
75
+ 修掉新增凭据(`DSH_MASTER_LLM_API_KEY`、`DSH_MASTER_GITHUB_TOKEN`、`DSH_ADAPTER_TOKEN`)漏脱敏的缺口;
76
+ 脱敏作用于 assistant 内容、工具结果、步骤记录与错误信息;
77
+ - 测试新增 2 例(凭据形态全收 + mandate 不可放宽),全量 **143/143 通过**。
78
+
79
+ ### Worker 看护 / Ticket→会话仓映射 / PR 交付(补充)
80
+ - **派发超时看护**:Router 每 60s 巡检 `dispatched`/`running` 工单,超过 `dispatchTimeoutMs`(默认 15 分钟)
81
+ 无终态 → 判 `failed(worker-timeout)`、广播 `timeout` 事件、**自动释放并发配额**;看护计数进状态接口;
82
+ - **Ticket→3_Sessions 会话映射**:派发时记录 `{ticketId, sessionKey(threadId), sourceId, status, dispatchedAt}`,
83
+ done/failed 时补终态与 `finishedAt`;`GET /dsh-master/api/superagent/session?ticketId=` 可按工单查会话映射,
84
+ 状态接口 `sessions` 暴露计数与最近映射(不含凭据);
85
+ - **PR 交付**(`src/superagent/pr-delivery.ts`):`host-pushes-branch-then-pr` 模式——
86
+ 分支由宿主/分身 git 凭据推送,Router 用宿主 token 调 GitHub API 开 PR;worker 结果带
87
+ `pr {branch,title,body,base,draft}` 时 done 后自动开 PR 并广播 `pr` 事件;
88
+ `pushFile()` 允许宿主用同一 token 推文件到新分支(**Worker 永不持 push 凭据**);
89
+ - 修复 `pushFile` 对响应体读取的脆弱性(统一 `readBody()`,兼容测试替身/异常实现);
90
+ - 测试新增 `superagent-pr-delivery.test.mjs`(5 例);全量 **141/141 通过**。
91
+
92
+ ### token 自动轮换与审计(桥 + 流式)
93
+ - **桥 token**(`POST /dsh-master/api/bridge/spawn` 使用的 `bridgeToken`):
94
+ 新增 `src/superagent/bridge-tokens.ts`,支持按 `bridgeTokenRotateMs`(默认 30 分钟)自动轮换,
95
+ 旧 token 在 `bridgeTokenGraceMs`(默认 5 分钟)内继续可用;配置的静态 token 作为长期 token 仍然有效;
96
+ 持久化只落 **sha256 摘要**(`dataDir/bridge-tokens.json`,0600),进程重启后仍可校验;
97
+ `rotateBridgeToken()` 提供手动轮换,返回新 token(只回一次);
98
+ - **审计**:桥与流式 token 动作统一写入 `dataDir/token-audit.jsonl`(append-only,0600),
99
+ 字段为 `at/scope/action/tokenId/…`,**不含明文 token**;内存审计环形日志保留最近 N 条;
100
+ - **流式 token**:新增 `auditSink` 落盘与 60s 定时 `sweep()`(过期自动清理);UI token 仍由前端每 4 分钟轮换;
101
+ - **状态接口**:`/dsh-master/api/status` 的 `bridge.tokens`(state/retiringAt/nextRotationAt/rotations/counts)
102
+ 与 `bridge.tokenAudit`、Router 的 `streaming.tokens` 均不含密钥;
103
+ - 测试 `test/superagent-token-rotation.test.mjs`(6 例):静态 token、宽限重叠/过期、摘要持久化与重启恢复、
104
+ 定时轮换开关、审计不含明文、流式审计落盘与定时清理。
105
+
106
+ ### 真实 streaming(provider SSE)+ 宿主 adapter + 契约包一致性
107
+ - **真实流式**:`worker/llm-http.ts` 新增 `chatStream()`,走 OpenAI 兼容 `stream: true` + SSE,
108
+ 边收边回调 content delta;tool_calls 按 index 聚合片段;usage 取末块;`[DONE]` 终止;
109
+ provider 忽略 stream 参数时自动回退普通 JSON(只回调一次,不重复);
110
+ - **Agent Loop 接线**:`callLLM()` 优先 `chatStream`,真实 delta 直送 sink;已真实流式时
111
+ 不再分块模拟(`streamedThisStep`),无 `chatStream` 的环境保留原分块兜底;
112
+ - **宿主 adapter 层**(`src/superagent/stream-adapter.ts`):SSE/WS 传输由宿主决定;
113
+ 宿主可注入 `dshMasterStreamAdapter` 服务(`{ publish(event, text), heartbeat?, close? }`),
114
+ Router 只产生事件;内置 Node SSE 仍为默认;新增 300 条环形回放、心跳、断连清理;
115
+ - **前端**:房主抽屉新增真实流式文本尾部展示与「工具中:xxx」,SSE 状态显示宿主 adapter;
116
+ - **契约包**:`@twinsearth/dsh-fang-contract@1.0.0` 已在 npm 发布;新增
117
+ `test/contract-conformance.test.mjs`(6 例)对比发布包与内嵌副本:导出面、常量、方法表、
118
+ 错误码、传输顺序全等,并做「发布版 server × 内嵌 client」「内嵌 server × 发布版 client」双向往返;
119
+ - 测试新增 `worker-llm-stream.test.ts`(4)、`worker-agent-stream.test.ts`(2)、
120
+ `superagent-stream-adapter.test.mjs`(5);合计 **130/130 通过**。
121
+
122
+ ### Worker preset 打包/接入 bundle 行(补充)
123
+ - `dist-worker` 作为独立 bundle 行 `master-superagent-loop` 接入;行配置新增 `enabled/autorun/model/workspace`(空串视为未配置);
124
+ - preset 补齐 Cordis 行契约:`export const name`、`export const inject = ['dshMaster']`、`apply(ctx, config)` 支持 `enabled:false` 跳过;
125
+ - fork 角色门禁前置:非 fork 角色直接返回 `role-not-allowed:<role>`,不再先注册再判断;
126
+ - 向房主核心注册 `superagent-loop` 行(capabilities: worker-agent-loop/llm-tool-loop/streaming-events/result-writeback),宿主状态不再显示“未激活却跑过循环”;
127
+ - `DSH_MASTER_TICKET` 解析容忍 BOM/空白(Windows 脚本注入常见),不再静默 `ticket-invalid`;
128
+ - 新增 `test/worker-preset-packaging.test.mjs`(5 例):export 指向 dist-worker、编译产物齐全、行名→package exports 全解析、enabled/autorun 门控、注册与角色门禁。
129
+
130
+ ### TypeScript 构建链(host + worker)
131
+ - 房主 `src/**/*.ts`(16 个文件)迁移为 TypeScript 源码,`tsconfig.host.json`(noEmit typecheck)+ `tsconfig.host.build.json` → `dist-host/`;
132
+ - Worker `worker/**/*.ts` 严格类型检查(strict)+ `tsconfig.worker.build.json` → `dist-worker/`;
133
+ - package exports/`cordis.patch.yml` 行名不变,运行时加载 `dist-host`/`dist-worker` 编译 JS;
134
+ - 浏览器 `client.js` 保持 JS;公开契约类型仍在 `types/superagent.d.ts`;
135
+ - host 迁移文件暂带 `// @ts-nocheck`(行为优先、类型注解逐步补齐),Worker 已 strict 检查。
136
+
137
+ ### Worker 结果回写(补充)
138
+ - Worker 的 LLM 工具循环早已实现(`worker/agent-loop.ts`,tsc 编译进 `dist-worker/`,真实 smoke 已验证 LLM 请求与循环);
139
+ - `create_pr` 工具接入真实 GitHub PR 客户端(`worker/github-pr.ts`,env `DSH_MASTER_GITHUB_TOKEN/REPO/BASE`,默认 fail-closed);
140
+ - Router 回写新增飞书自定义机器人 webhook(text 摘要,可选 HMAC 签名);GitHub Issue 评论回写已有;
141
+ - 回写配置默认关闭,失败只告警;token 不进日志/状态。
142
+
143
+ ### 真实 Host 集成 smoke(2026-11-11)
144
+ - 双 Host 跨进程派发桥 smoke:原身 Host Router → file outbox → 母体 Fang 契约 → 真实 fork → Worker → stub LLM → SSE done;
145
+ - 修复 dispatch/done 竞态(Worker done 先到会被 dispatched 覆盖);新增回归测试;
146
+ - 临时 DSH_HOME/profile 安装 dsh-fang 3.1.15 + dsh-master 3.2.5,真实 Host --port 18188;
147
+ - 契约 HTTP(双 token)hello/health/fork_list 全部 200;Master 内嵌 SDK 客户端 ransport=http 成功;
148
+ - ang.fork.spawn 派发真实 fork(pid/port/forkSeed 成功);Worker preset 在 fork 中自动运行;
149
+ - 本地 OpenAI 兼容 stub 收到真实 LLM 请求(ticket prompt + 5 工具 schema);详见 docs/SMOKE-3.2.5.md。
150
+
151
+
152
+
153
+ **主题:前端实时事件流 + token 轮换/审计 + Worker 并发配额。**
154
+
155
+ ### 新增
156
+ - **SSE 实时事件流**:Router 新增 GET /dsh-master/api/superagent/stream( ext/event-stream);
157
+ Worker 事件实时广播到浏览器;离线回放最近事件;15s heartbeat;断线自动重连;
158
+ - **UI stream token**:POST /dsh-master/api/superagent/stream-token 签发/轮换短 TTL token;
159
+ SSE 默认要求 UI token(streamTokenRequired),避免把 worker token 暴露给页面;
160
+ - **token 管理**(src/superagent/stream-tokens.mjs):签发/校验/轮换/撤销/TTL/sweep + 审计环形日志;
161
+ worker token 只用于 worker-events,done 后撤销;审计记录不含原始 token;
162
+ - **Worker 并发配额**:workerQuota {enabled,maxConcurrent,maxPerSource};超限返回
163
+ worker-quota-exceeded 并落 Ticket=unavailable,不 spawn;done 后自动释放配额;
164
+ - 前端「房主」抽屉新增实时事件流卡片:显示 SSE 连接数、并发配额、最近 Worker 事件,
165
+ UI token 每 4 分钟轮换并重连;
166
+ - 测试:token 管理、SSE token/广播/撤销、配额拒绝与释放、事件审计(104/104 全绿)。
167
+
168
+ ### 配置
169
+ `yaml
170
+ streamTokenTtlMs: 21600000
171
+ uiTokenTtlMs: 600000
172
+ streamTokenRequired: true
173
+ workerQuota:
174
+ enabled: true
175
+ maxConcurrent: 2
176
+ maxPerSource: 0
177
+ `
178
+
179
+ ### 边界
180
+ - 事件流为只读;不含 LLM 完整上下文/密钥;SSE token 需定期轮换;
181
+ - 配额为严格拒绝(暂不排队);跨 Host 配额由 Router(essence)单点统计;
182
+ - 未发布;等审核/smoke 通过后按指令发布。
183
+
184
+ # Changelog
185
+
186
+ ## 3.2.4(2026-11-11,发布)
187
+
188
+ **主题:房主与瓮城独立互联契约(fang-master contract 1.0)+ 保底通讯 + 独立升级/替换。**
189
+
190
+ ### 新增
191
+ - **内嵌契约 SDK** `src/contract/`(与 `@twinsearth/dsh-fang-contract` 1.0.x 同源、同版本号):
192
+ - 版本协商(hello/contractVersion/methods/capabilities)、标准信封、错误码、传输路由器;
193
+ - 四级保底:`local` DSH 服务 → `http` `/fang/api/contract/*` → `file` outbox → `legacy` 旧服务键;
194
+ - `unsupported-method/version`、传输失败才降级;业务错误不重试,避免重复副作用;
195
+ - Router 派发优先走契约:
196
+ - 配置 `dispatch.contract: true` 后,spawn 先经 `fangContract`(local/http/file/legacy);
197
+ - 契约全失败再回退既有的本地 forker / 母体 bridge;
198
+ - 状态 `describe()` 暴露 contract 路由/尝试记录(不含 token);
199
+ - 文档 `docs/INTEROP.md`:方法表、信封、四级 fallback、独立升级/替换流程、npm staged publishing 说明;
200
+ - 测试新增:本地契约、HTTP、无传输 fail-closed、legacy 服务键降级。
201
+
202
+ ### 配套
203
+ - 瓮城 dsh-Fang **3.1.15**:内嵌同一契约 SDK;mother 提供 `fangContract` 服务与
204
+ `/fang/api/contract/{hello,invoke,health}`;contract token 未配置时 HTTP 端点禁用;
205
+ 可选文件 outbox server;`SERVICE.contract='fangContract'`;AUTO 兼容旧版本。
206
+
207
+ ### 安全
208
+ - 契约 HTTP 必须 Bearer token(常量时间比较);env 只透传 `DSH_MASTER_*`;
209
+ - 状态/响应不返回 token/key;file fallback 依赖受控本机目录。
210
+
211
+ ### 边界
212
+ - npm 首次发布 `@twinsearth/dsh-fang-contract@1.0.0` 被 npm staged publishing 置为
213
+ `0.0.0-stage` 占位,待 2FA/stage 审批;本次两侧以“同源内嵌 + 独立源码仓”先行发布,
214
+ 协议/代码不变,npm 正式可用后可切换依赖而不改接口。
215
+ - 前端 SSE/WS、token 轮换审计、Worker 资源配额仍待 3.2.5+;
216
+ - 未做真实 Host 端到端 smoke(测试使用 fake forker/fetch/server)。
217
+
218
+ ## 3.2.3-dev.0(2026-11-11,未发布)
219
+
220
+ **主题:Worker preset 构建与 bundle 接入 + 跨进程派发桥 + 真实流式回传/回写 + 安全审计加固。**
221
+
222
+ ### 构建与接入
223
+ - `tsconfig.worker.build.json`:tsc 编译 `worker/` → `dist-worker/`(`rewriteRelativeImportExtensions`);
224
+ `npm run build:worker` 通过,产物可直接被 DSH 加载;
225
+ - `package.json` 的 `./superagent-loop` 指向 `dist-worker/index.js`,`files` 包含 dist;
226
+ - bundle 新增第 6 行 **`master-superagent-loop`**(fork only):有 `DSH_MASTER_TICKET` 的 fork
227
+ 自动跑 Worker Agent Loop,可用 `DSH_MASTER_WORKER_AUTORUN=0` 关闭;角色不对(母体/元主)直接拒绝;
228
+ - 新增 kernel 行 `ROW.superagentLoop` + 角色矩阵 + 状态目录(5 个子插件)。
229
+
230
+ ### 跨进程派发桥
231
+ - `dispatch.mjs` 支持两模式:本地 `fangForker.spawn`;或 HTTP 调母体房主核心
232
+ `POST /dsh-master/api/bridge/spawn`(Bearer `bridgeToken`);
233
+ - 母体 core 路由校验 token、ticket、dispatch 配置后调用 `fangForker.spawn(env)`;
234
+ 只透传 `DSH_MASTER_*` 环境;失败返回明确错误码,绝不本地降级执行;
235
+ - 状态接口 `bridge.enabled / dispatchConfigured`(不含 token)。
236
+
237
+ ### 真实 streaming 与回写
238
+ - Router 派发时生成 per-ticket stream token,注入
239
+ `DSH_MASTER_STREAM_URL` / `DSH_MASTER_STREAM_TOKEN`;
240
+ - Worker `sink-http.ts` 批量 POST phase/step/stream/log/done 到 Router
241
+ `/dsh-master/api/superagent/worker-events`;Router 校验 token+ticketId、落库事件、
242
+ done 时把 Ticket 置 done/failed 并消费 token;
243
+ - `writeback.mjs`:webhook 结果回调 / GitHub Issue 评论回写(默认关闭,按配置启用);
244
+ 回写失败只告警,不影响 Ticket 状态;状态接口不返回任何 secret。
245
+
246
+ ### 安全审计加固(v3.2.2 审计 P0/P1)
247
+ - Shell 使用**白名单环境变量**,剥掉 KEY/TOKEN/SECRET/`DSH_*`;
248
+ - Shell 超时/中止改为 **kill 进程树**(Windows `taskkill /T /F`,POSIX 进程组);
249
+ - 解释器 `node -e` / `python -c` 等纳入黑名单;
250
+ - 写文件默认拒绝 `.git`、`.dsh`、`.env`、`.ssh` 等敏感路径;
251
+ - fs 工具的 Mandate 改为**每次从 context.mandate 取**;Worker 校验 Ticket Mandate 与构造
252
+ Mandate 一致(`mandate-mismatch`),权限取交集;
253
+ - 工具结果/步骤/日志做 secret 脱敏(`redactSecrets`);provider 不返回 usage 时按字符估算
254
+ Token 预算;单条响应长度与 limits 绝对上限生效。
255
+
256
+ ### 测试
257
+ - 全量 **95/95 pass**(新增:bridge 派发/母体路由、streaming 鉴权/落库/done、writeback、
258
+ Worker HTTP sink、env 脱敏、解释器黑名单、敏感路径、进程树超时、mandate-mismatch、脱敏、token 兜底);
259
+ - `tsc -p tsconfig.worker.json`(strict)与 `tsc -p tsconfig.worker.build.json` 均通过。
260
+
261
+ ### 边界
262
+ - 真实 SSE/WS 到前端 UI 未实现(当前 Worker→Router HTTP 实时通道 + 只读事件查询);
263
+ - bridge/streaming/writeback 的 token 需宿主配置;默认全关;
264
+ - Shell 的 VM 物理隔离仍是主防线(黑名单只做 defense-in-depth);
265
+ - 未发布、未安装任何 profile。
266
+
267
+ ## 3.2.2-dev.0(2026-11-11,未发布)
268
+
269
+ **主题:Worker 内部 Agent Loop —— 多轮工具调用、熔断、安全沙箱工具、可观测与崩溃快照。**
270
+
271
+ ### 新增(TypeScript,`worker/`)
272
+
273
+ - **Agent Loop**(`worker/agent-loop.ts`):
274
+ - 状态机 `initializing → thinking → executing_tool → thinking → … → reporting → done`;
275
+ - 工具调用结果以 `role: tool` 回灌模型,循环直到模型不再返回 `tool_calls`;
276
+ - 硬熔断:`maxSteps`(15)、`maxTokens`(50k)、`maxWallClockMs`(15min)、
277
+ `maxContextChars`(400k)、连续相同工具调用死循环检测(默认 3 次);
278
+ - LLM 调用超时(120s)与分类错误(`llm-timeout` / `llm-call-failed` / `invalid-response`);
279
+ - 所有失败返回结构化 `WorkerResult`(不把异常抛给宿主);
280
+ - `WorkerStep[]` 审计 + `snapshot()` 崩溃现场恢复。
281
+ - **安全工具集**(`worker/tools.ts`):
282
+ - `fs_read_file` / `fs_list_dir`(workspace jail)、
283
+ `fs_write_file`(workspace jail + Mandate.scope,realpath 防符号链接逃逸)、
284
+ `exec_shell_in_vm`(必须 allowShell + 危险命令黑名单 + 超时/输出上限)、
285
+ `create_pr`(宿主注入 PR 客户端,默认拒绝);
286
+ - ToolRegistry 统一超时/AbortSignal/异常隔离;工具错误转 `执行报错` 文本回灌模型。
287
+ - **可观测**:`WorkerSink`(phase/step/stream/log)→ Cordis 事件转发;CLI `worker/main.ts`。
288
+ - **LLM 适配器**:`worker/llm-http.ts`(OpenAI 兼容 Chat Completions,tool_calls/usage 解析,key 不入日志)。
289
+ - **类型**:`worker/types.ts`(Ticket/Step/Phase/Limits/LLM/Tool/Result)。
290
+ - **工具链**:`tsconfig.worker.json`(strict + noEmit);`npm run typecheck:worker` 通过;
291
+ Node 22.6+ 类型擦除可直接运行 `.ts`;devDeps:typescript + @types/node。
292
+ - **测试**:79 项全绿(含 21 项 worker TS 测试:循环/工具调用/超时/熔断/死循环/路径 jail/黑名单/LLM 适配器)。
293
+
294
+ ### 变更
295
+
296
+ - 包版本 `3.2.1-dev.0` → `3.2.2-dev.0`;新增 export `./superagent-loop`;
297
+ - README/ROADMAP/SECURITY 增加 Worker Loop 说明。
298
+
299
+ ### 已知限制
300
+
301
+ - Worker preset 尚未打包为已发布 bundle(tsc 构建产物在 3.2.3);
302
+ - 跨进程 Router→DerivedManager 桥、真实 SSE/WS streaming、PR/评论/飞书回写待 3.2.3;
303
+ - `exec_shell_in_vm` 的 >5s 长任务后台化需宿主 `vm_job_submit` 接入(3.2.3);
304
+ - 未发布、未安装任何 profile。
305
+
306
+ ## 3.2.1-dev.0(2026-11-11,未发布)
307
+
308
+ **主题:引入 SuperAgent —— Router / Worker 双层架构落地。**
309
+
310
+ ### 新增
311
+
312
+ - **Router(`master-superagent-router`,essence only)**:
313
+ - GitHub Webhook(HMAC-SHA256 验签,`issue_comment` / `pull_request_review`);
314
+ - 飞书 Webhook(verification token、`url_verification` challenge、`im.message.receive_v1` 文本);
315
+ - SourceEvent 归一化、事件去重(500 条 LRU);
316
+ - Ticket + 不可变 Mandate(scope/policyVersion/strength/allowedSources);
317
+ - 渐进式信任 `off / observe / auto`(默认 observe);确定性 Gate(actor/仓库/mention/bot);
318
+ - Ticket 持久化(可选 `dataDir`,JSON 原子写);
319
+ - 经 `fangForker.spawn({env})` 派发 Worker;缺服务/配置 → `dispatch-unavailable`(不本地执行)。
320
+ - **Worker(`master-superagent-worker`,fork only)**:
321
+ - 从 `DSH_MASTER_TICKET` 环境变量恢复/校验 Ticket;
322
+ - `assertMandateScope` 精确匹配,越权 `out-of-mandate` 退回 Router;
323
+ - Worker prompt(含注入防护与交付边界);
324
+ - `planShellCommand`:>5 秒 Shell 命令必须后台化。
325
+ - **类型**:`types/superagent.d.ts`(SourceEvent / Mandate / Ticket / EvalDecision / TrustMode)。
326
+ - **文档**:`docs/SUPERAGENT.md`(双层结构、契约、灰度上线、限制);SECURITY/ARCHITECTURE/ROADMAP 同步。
327
+ - **测试**:58 项全绿(types/trust/sources/router/worker/core/kernel/cost/dual/package-contract)。
328
+
329
+ ### 变更
330
+
331
+ - 3.2.0 的单行 `master-superagent` 拆分为 `master-superagent-router` + `master-superagent-worker`;
332
+ - 角色矩阵:Router essence-only、Worker fork-only、母体不接纳任何 SuperAgent 行;
333
+ - 包版本 `3.2.0-dev.0` → `3.2.1-dev.0`。
334
+
335
+ ### 已知限制
336
+
337
+ - Router 在 essence 内派发需要瓮城跨进程 DerivedManager 桥(3.2.2);桥前 auto 模式不可用;
338
+ - Worker preset 的 LLM 工具循环、结果回写(PR/评论/飞书)未实现;
339
+ - 飞书加密事件、GitHub 多仓库 secret 轮换待 3.2.2;
340
+ - 未发布、未安装任何 profile。
341
+
342
+ ## 3.2.0-dev.0(2026-11-11,未发布)
343
+
344
+ **主题:v3.2.0 第一步 —— 房主 dsh-Master 与三大 Agent 子插件架构骨架。**
345
+
346
+ ### 新增
347
+
348
+ - 新仓库 / 新 bundle:`@twinsearth/dsh-master`(房主),与瓮城 `dsh-Fang` 并行;
349
+ - 主 Agent 控制面 `master-core`:
350
+ - `dshMaster` 服务:`status()` / `health()` / `registerSubplugin()` / `cooperation()`;
351
+ - 只读路由 `GET /dsh-master/api/status`;
352
+ - Web Client:侧栏 `sidebar.footer.action`「◈ 房主」+ 只读状态抽屉(子插件矩阵、瓮城服务可用性)。
353
+ - 子插件 1 `master-superagent`(**fork only**):
354
+ - 事件评估(来源/权限/价值/仓库允许列表/bot/标签);
355
+ - dry-run 工作项计划;live 经瓮城 `fangForker.spawn` 派发,缺服务 fail-closed。
356
+ - 子插件 2 `master-cost-optimizer`(**fork only**,observe-only):
357
+ - token 预估(HarnessMM 基准 96,280→11,620,节省 87.93%)、实测记录、节省/成功率汇总;
358
+ - 明确不拦截/不改写模型调用;EGD/GDR/CCS 留到 3.3.0。
359
+ - 子插件 3 `master-dual-manager`(**mother/essence only**):
360
+ - PM:结构化 PRD、`askUser` 走瓮城决策中心;
361
+ - PJM:PRD→步骤计划、`dispatch` 经 `fangForker.spawn` 调度、`completeStep` 状态机;
362
+ - 无协作服务时 fail-closed,不本地执行。
363
+ - 角色矩阵在 `src/kernel.mjs` 集中定义并被 apply 强制;bundle patch 只 insert 自己的 4 行。
364
+ - 文档:`docs/ARCHITECTURE.md`、`docs/ROADMAP.md`(3.2.0–3.4.0)、`docs/SECURITY.md`、`locale/{zh,en}.json`、`icon.svg`。
365
+ - 测试:kernel / core / superagent / cost / dual / package-patch 契约(node:test,无运行时依赖)。
366
+
367
+ ### 边界
368
+
369
+ - 未安装到任何 profile;未发布 npm;未打 GitHub Release;
370
+ - 不发起真实事件源网络请求;不持久化;PM/PJM 尚未接 LLM 提示词与工具循环。
371
+
372
+ ### 下一步
373
+
374
+ - 3.2.1:GitHub/飞书事件适配器;
375
+ - 3.2.2:SuperAgent 结果回写;
376
+ - 3.3.0:HarnessMM EGD/GDR/CCS;
377
+ - 3.4.0:PM/PJM 元 Agent 提示词与工具循环。
@@ -0,0 +1,60 @@
1
+ # 房主 ↔ 瓮城 互联契约(v3.2.4)
2
+
3
+ > 目标:**双方独立升级/发布,仍能互联互通**;接口架构可通过更新契约包整体替换,
4
+ > 同时保留多级保底通讯。
5
+ > 实现:`@twinsearth/dsh-fang-contract` 1.0.x(源码独立仓,另见 `E:\GPT\dsh-fang-contract`),
6
+ > 两侧各自内嵌**同一份** `src/contract/` 源码(无运行时 npm 依赖),版本号一致。
7
+
8
+ ## 1. 契约内容
9
+
10
+ - 方法表:`contract.hello/health`、`fang.fork.spawn/stop/list`、`fang.decision.create/resolve`、
11
+ `fang.session.list`、`fang.orchestrator.status`;
12
+ - 信封:`protocol=fang-master, protocolVersion=1, id, method, params, meta`;
13
+ - 版本协商:`hello` 返回 `contractVersion / role / methods / capabilities / transports`,
14
+ `negotiate()` 裁剪双方方法交集;MAJOR 不兼容时自动降级;
15
+ - 错误码:`unsupported-method / unsupported-version / transport-* / all-transports-failed` 等。
16
+
17
+ ## 2. 四级保底传输
18
+
19
+ ```text
20
+ local 同 Host DSH 服务 fangContract(零网络,首选)
21
+ ↓ 不可用/超时
22
+ http POST /fang/api/contract/{hello,invoke}(Bearer token)
23
+ ↓ 不可用/超时
24
+ file 同一文件系统 outbox/inbox(requests/*.json → responses/*.json)
25
+ ↓ 不可用/超时
26
+ legacy 直接调用 3.1.x 旧服务键(fangForker / fangDecisionCenter 等)
27
+ ```
28
+
29
+ 业务错误(如 `ticket-invalid`)**不降级**,避免重复副作用;传输/协议/未知方法才降级。
30
+ 每次尝试记录在 `client.attempts()`,状态可观测。
31
+
32
+ ## 3. 两侧实现位置
33
+
34
+ | 侧 | 文件 | 内容 |
35
+ |---|---|---|
36
+ | 瓮城 dsh-Fang v3.1.15 | `src/contract/` + `src/plugins/orchestrator.mjs` | 内嵌契约 SDK;mother 提供 `fangContract` 服务;HTTP `/fang/api/contract/*`;可选 file outbox server |
37
+ | 房主 dsh-Master v3.2.4 | `src/contract/` + `src/superagent/dispatch.mjs` | 内嵌同一 SDK;派发优先 contract(local/http/file/legacy),失败再回退本地 forker/母体 bridge |
38
+
39
+ 两侧都不 import 对方内部源码,只依赖契约包稳定接口。
40
+
41
+ ## 4. 独立升级 / 完全替换流程
42
+
43
+ 1. 修改并发布契约包(源码仓 `dsh-fang-contract`,版本 `x.y.z`);
44
+ 2. 将 `src/contract/` 同步到两侧(同源文件,`CONTRACT_VERSION` 一致);
45
+ 3. MINOR:双方可不同时升级;`hello` 协商后使用方法交集,旧端自动降级;
46
+ 4. MAJOR:新方法同时保留 `method@old` 一个 MINOR 周期(双写),两侧逐侧升级;
47
+ 5. 观察 `client.attempts()` / `describe()` 的 transport 命中与降级;
48
+ 6. 旧 MAJOR 下线前至少保留一个 MINOR 周期的 legacy 传输。
49
+
50
+ > npm 上 `@twinsearth/dsh-fang-contract@1.0.0` 首次发布被 npm **staged publishing**
51
+ > 置为 `0.0.0-stage` 占位(需 2FA/stage 审批后才能成为正式版本);
52
+ > 本次两个主包采用“同源内嵌 + 独立源码仓”的方式先行发布,待 npm 正式可用后
53
+ > 可改为依赖 npm 包,无需改协议/代码。
54
+
55
+ ## 5. 安全
56
+
57
+ - HTTP 契约必须 Bearer token(两侧各自配置 `contract.token` / `dispatch.motherToken`);
58
+ - env 只透传 `DSH_MASTER_*`;契约响应/状态不含 key/token/私钥;
59
+ - file outbox 目录须在受控本机路径,由 OS 账户隔离;
60
+ - legacy 传输只调用既有服务键,不扩大权限。
@@ -0,0 +1,121 @@
1
+ # dsh-Master v3.2.7 全面审计、修复与实机复盘
2
+
3
+ 日期:2026-11-12。对象:`E:\GPT\dsh-master`,基线 `822ab2b`(已发布 3.2.7)+ 本工作树后续修复。
4
+
5
+ > 本文是**工程验收记录**,不是发布声明。后续修复未发布,未安装用户主 profile,瓮城项目未改动。
6
+
7
+ ## 1. 结论
8
+
9
+ - 基线门禁:161/161 通过,但只读审计发现 **P0×1、P1×7、P2×25**,以及测试覆盖/假通过/残留问题;原 56 条需求矩阵为完成 31、部分 21、未完成/不符 4。
10
+ - 本轮直接修复 Worker、Router、契约、PR、飞书、SSE 客户端、PJM 与测试基础设施的关键缺陷,并新增行为回归。
11
+ - 最终门禁:**`check` 0 error、`build` 0 error、`npm test` 185/185、`test:clean` 185/185**。
12
+ - 真实双 Host/fork 最终 **17 项断言全部通过**:真实工具写读、结果落库、HTTP 回写、SSE 分批、鉴权、去重、配额释放、文件桥结算后零残留。
13
+ - 真实浏览器点验通过:UI token 轮换、SSE 卡片、终态显示、截图证据齐全。
14
+ - 不宣称所有路线图均完成:HarnessMM 高级优化、自然语言 PM、完整 PJM 健康闭环、可验证 VM attestation 仍是后续版本范围。
15
+
16
+ ## 2. 修复清单(审计发现 → 实现 → 证据)
17
+
18
+ ### 2.1 Worker / Agent Loop / 工具
19
+
20
+ | 原问题 | 修复 | 回归证据 |
21
+ |---|---|---|
22
+ | prompt 教 `read_file/write_file/execute_shell`,实际工具不存在 | 改为 `fs_read_file/fs_write_file/exec_shell_in_vm` | `worker prompt: every advertised tool name resolves in the real registry`,真实 schema 验证 |
23
+ | A/B 周期检测硬编码 3 周期,压过配置且误杀正常循环 | period=1 遵守连续阈值;period≥2 默认 `maxIdenticalToolRepeats+1` 周期,放大配置不再失效 | cycle 默认/长周期/合法变化/放大配置测试;连续 3 次允许、第 4 次拒绝 |
24
+ | sink POST 无超时,flushing 早退可让 close 永久等待 | 每次请求 AbortController;close 有总时限,即使 fetch 不响应 abort 也能返回 | 挂起 POST、非协作 fetch、网络失败真实断言 |
25
+ | runShell 成功也 taskkill;中止后可能不结算 | 成功 close 直接结算;超时/中止杀树后 500ms 有界结算;清理 signal/timer | 既有逃逸/杀树测试 + 全套 clean 退出 |
26
+ | GitHub/飞书逻辑 scope 被当成不存在目录 | 含 `#` 或 `:` 的逻辑 scope 回退 workspace,明确路径才收窄 | `mandate jail: logical Feishu/GitHub scopes...` |
27
+ | >5s Shell 仍同步阻塞 | 超过阈值返回后台 job id;`vm_job_result` 查询真实终态;结果 10min 过期、最多 50 job | Windows `ping` 真实后台执行与输出断言 |
28
+ | HarnessMM 未接 Worker usage | fork 完成后记录真实 token 与成功状态;优化前后相等,不虚报节省 | `cost observe: worker completion records real token usage...` |
29
+ | 失败后 autoStartedTicket 永久卡死 | 完成/异常均清空启动标记,允许后续 ticket | autorun 代码路径 + 实机连续多票 |
30
+
31
+ ### 2.2 Router / 生命周期 / 鉴权
32
+
33
+ | 原问题 | 修复 | 回归证据 |
34
+ |---|---|---|
35
+ | dispatch 抛异常导致 token 不撤销、session 不终结、配额死锁 | try/catch 全生命周期:落 failed、撤销 worker token、更新 session;watchdog 覆盖 pending | 连续两次 spawn 抛错均 failed、active=0,不出现 quota-exceeded |
36
+ | watchdog 只看 dispatched/running 和 updatedAt,可能误杀健康长任务 | 覆盖 pending,参考最近 worker event 时间;终态不被 timeout 覆盖 | 生命周期/状态 race 测试 |
37
+ | `GET /superagent/session` 文档有、路由无 | 注册查询;缺参 400、未知 404、命中 200 | 路由三态测试 + 实机 done 映射 |
38
+ | worker-events GET 匿名返回工具正文 | 要求 UI token 或匹配 ticket 的 worker token;错 ticket 403 | 匿名 401、UI 200、worker 错票 403,实机复核 |
39
+ | 任意旧 token 都能 rotate 出新 UI token | rotate 先 verify,再 revoke+issue;未知/过期/类型不符拒绝 | 旧 token 重放 401;真实浏览器轮换 200/旧用 401 |
40
+ | 同一路径 GET/POST 注册两次,DSH 按 kind+path 去重导致 GET 被吞 | EVENTS_PATH 只注册一次,handler 内按 method 分流 | fake webServer 也按 kind+path 拒绝重复;真实 Host 原先 401 的 GET 修后 200 |
41
+ | 首次 UI token 任意来源可签 | 默认仅 loopback;可选 `streamBootstrapToken` 强制 Bearer | 回环 200;配置路径保留受控远程部署 |
42
+
43
+ ### 2.3 契约 / 派发
44
+
45
+ | 原问题 | 修复 | 回归证据 |
46
+ |---|---|---|
47
+ | idempotencyKey 在 transport 丢失 | local/http/file 全部写入 envelope.meta;per-call timeout 同时下传 | local/HTTP 实际 envelope 断言;file 真请求元数据断言 |
48
+ | file 传输无真实测试、临时文件可能残留 | 真请求/响应、超时清理;成功响应后调用方删除请求;Windows 持锁有界重试 | 服务不删请求、Windows 文件句柄锁两种回归;实机结算后 requests/responses 均空 |
49
+ | per-call timeout 不生效 | HTTP 使用本次调用 timeout,AbortSignal 真实触发 | 30ms 超时断言 |
50
+ | dispatch status 看不到传输尝试 | `dispatch.contract.attempts` 暴露,不含 secret | 实机确认 transport=file、ok=true |
51
+ | 重试可能重复起分身 | ticket.id 作为 idempotencyKey 贯通;重复 webhook 由 event id 去重 | 实机重复 delivery 返回 duplicate-event,无第二 fork |
52
+
53
+ ### 2.4 PR 交付
54
+
55
+ | 原问题 | 修复 | 回归证据 |
56
+ |---|---|---|
57
+ | 生产调用的 `create()` 绕过护栏 | create/pushFile/deliver 全部统一分支与路径校验;拒绝 owner:branch、受保护 head、非法 base | main、跨仓、穿越、控制字符、workflow 等均在零网络调用下拒绝 |
58
+ | `deliver()` 无调用者、WorkerResult 无 pr | WorkerResult 可携带 pr;Router 有 files 走 deliver,无 files 走 create | deliver 真推送文件→开 PR;第二次复用 open PR,不重复创建 |
59
+ | GitHub fetch 无超时 | 全部请求 AbortController;错误不含 token | timeout/abort 与 token 不泄漏断言 |
60
+ | 分支 hash 可能被截断 | 不在末尾截掉 hash;分支整体有 200 字符与字符白名单 | 分支末尾 8 位 hash 断言 |
61
+
62
+ ### 2.5 事件源 / UI / PJM
63
+
64
+ - 飞书:AES-256-CBC(SHA-256 Encrypt Key、密文前 16 字节 IV)解密,正确事件归一化;错 key/坏密文/错 verification token 全部 fail-closed。
65
+ - LiveFeed:轮换携带当前 token;卸载关闭 EventSource/timer 并清空队列;done 后不再显示「工具中」。
66
+ - PJM:spawn 改用 `homeDir/cliPath/profile/taskTitle/env`;先占位再 await,两个并发 dispatch 只派生一次。
67
+ - `cordis.patch.yml`:`streamToken*` 与 `workerQuota` 移到 Router 顶层,修复配置写了不生效;测试锁定层级。
68
+
69
+ ## 3. 测试与覆盖
70
+
71
+ | 项目 | 基线 | 最终 |
72
+ |---|---:|---:|
73
+ | 测试 | 161 pass | **185 pass / 0 fail** |
74
+ | 无 force-exit 干净退出 | 未单独验证 | **185 pass / 0 fail,11.88s** |
75
+ | client.js 行覆盖 | 0% 行为测试,只有源码 grep | **95.35%**(Node coverage,含真实模块行为路径) |
76
+ | pr-delivery.ts 行覆盖 | 62% | **94.16%** |
77
+ | 历史测试临时目录 | 审计实测 136 个 `dsh-master-tokens-*` | 清理 138 个各类测试目录;最终 `[]` |
78
+ | 假/浅测试 | 同义反复、永真断言、零断言、2.5s 假通过窗口 | token 定时轮换改真实等待;永真断言改 public API 非泄密;sink 网络失败补真实计数;后台 job 用真实进程输出 |
79
+
80
+ 限制:Worker `index.ts` 的完整 Cordis autorun 分支仍以真实 Host E2E 补足,不能只用行覆盖率代表全部风险;Host 仍有 `@ts-nocheck` 文件,严格类型治理未全部完成。
81
+
82
+ ## 4. 实机部署与性能
83
+
84
+ 详见 `SMOKE-3.2.7.md`。最终票:
85
+
86
+ ```text
87
+ Webhook 202 9ms
88
+ fork 预置至首个 Worker 事件 5,228ms
89
+ Worker Agent Loop 1,963ms
90
+ Worker 完成 7,191ms
91
+ spawn 完整结算/桥清理 60,508ms
92
+ SSE at 间隔 188ms / 187ms
93
+ ```
94
+
95
+ 三次连续派生保留完整波动:5.469s / 61.770s / 60.744s。结论:Webhook 与 Worker Loop 较快且稳定,**fork/Host 派生等待是主要瓶颈且波动大**;不能把单次 7 秒写成稳定 SLA。
96
+
97
+ ## 5. 需求完成度重评
98
+
99
+ 审计时 4 个「未完成/与文档不符」均有本轮实现与测试:
100
+
101
+ - R49 PR 交付:可达且有护栏、幂等、真实调用测试;
102
+ - R53 session 路由:已实现并实机验证;
103
+ - R12 飞书 Encrypt Key:已实现并测试;
104
+ - R33 长 Shell 后台化:已实现真实 job 与轮询。
105
+
106
+ 次级缺口同步修复:Mandate 逻辑 scope、契约幂等/超时/尝试记录、patch 配置层级、PJM spawn 契约、UI token 轮换、成本实测接线、文档过期。
107
+
108
+ **不机械宣称 100%**:原 56 条矩阵需要按新证据重新逐条验收;HarnessMM EGD/GDR/CCS、PM 自然语言、完整 PJM 健康闭环属于后续版本,不能计入当前完成。
109
+
110
+ ## 6. 剩余风险与建议优先级
111
+
112
+ 1. **P1 性能**:Fang/Host 派生长尾 57–60s。建议记录 spawn 接收/开始预置/首事件/响应四个时间戳,定位锁、复制、扫描与进程退出等待;不要把 Worker done 当 spawn settled。
113
+ 2. **P1 安全**:VM attestation 当前是部署方显式声明,不是可验证证明;生产开启 Shell 前必须接真实隔离测量。
114
+ 3. **P1 类型**:Host 多文件 `@ts-nocheck`,建议按 superagent 域逐步恢复 strict,而不是一次性掩盖。
115
+ 4. **P2 可观测**:ticket store 仍 JSON 全量原子写,事件量很大时需增量/归档;workerEvents 需要按 ticket 淘汰策略与跨 Host Router 单例。
116
+ 5. **P2 测试**:补 worker/main.ts CLI、完整 autorun 分支、真实 Feishu HTTP 加密入口;浏览器测试保留为发布前 smoke。
117
+ 6. **P3 路线图**:HarnessMM 高级优化、自然语言 PM、完整 PJM 健康闭环明确留给 3.3/3.4,不在本补丁虚报完成。
118
+
119
+ ## 7. 发布状态
120
+
121
+ 本轮没有 npm publish、没有新 tag、没有 Release、没有安装主 profile。`npm pack` 仅用于隔离测试环境加载。若要形成 3.2.8 或后续发布,需另经用户明确指令与最终 diff 审核。