@zhushanwen/subagent-core 0.6.0 → 0.7.0

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 (278) hide show
  1. package/README.md +1 -1
  2. package/dist/chunk-KXVBIVOU.js +16 -0
  3. package/dist/chunk-T2SYBW3I.js +24 -0
  4. package/dist/chunk-VURUAGMM.js +2305 -0
  5. package/dist/{types-C3fE3R9x.d.cts → engine-discovery-scan-ocpM8FmI.d.cts} +770 -668
  6. package/dist/{types-C3fE3R9x.d.ts → engine-discovery-scan-ocpM8FmI.d.ts} +770 -668
  7. package/dist/execution/engine/engine-discovery-scan.cjs +2210 -0
  8. package/dist/execution/engine/engine-discovery-scan.d.cts +4 -0
  9. package/dist/execution/engine/engine-discovery-scan.d.ts +4 -0
  10. package/dist/execution/engine/engine-discovery-scan.js +20 -0
  11. package/dist/execution/engine/paths.cjs +6 -23
  12. package/dist/execution/engine/paths.d.cts +1 -8
  13. package/dist/execution/engine/paths.d.ts +1 -8
  14. package/dist/execution/engine/paths.js +1 -1
  15. package/dist/execution/relay-env.cjs +12 -28
  16. package/dist/execution/relay-env.d.cts +1 -33
  17. package/dist/execution/relay-env.d.ts +1 -33
  18. package/dist/execution/relay-env.js +5 -3
  19. package/dist/index.cjs +14045 -16059
  20. package/dist/index.d.cts +1035 -1579
  21. package/dist/index.d.ts +1035 -1579
  22. package/dist/index.js +9838 -13800
  23. package/dist.bundle/index.cjs +28875 -30323
  24. package/package.json +20 -26
  25. package/src/__tests__/record-store-last-line.test.ts +16 -7
  26. package/src/core/error-message.ts +7 -6
  27. package/src/core/host-services.ts +8 -2
  28. package/src/core/notify-ports.ts +17 -2
  29. package/src/execution/__tests__/chat-engine-routing.test.ts +62 -28
  30. package/src/execution/__tests__/chat-round-first-round-watchdog.test.ts +255 -0
  31. package/src/execution/__tests__/collect-coordinator-service.test.ts +36 -47
  32. package/src/execution/__tests__/collect-mixed-dispatch.test.ts +20 -53
  33. package/src/execution/__tests__/delivery-methods.test.ts +179 -237
  34. package/src/execution/__tests__/execute-and-await-worktree.test.ts +0 -2
  35. package/src/execution/__tests__/execute-nesting.test.ts +20 -13
  36. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +20 -33
  37. package/src/execution/__tests__/gc-timer.test.ts +7 -22
  38. package/src/execution/__tests__/get-record-for-action-restart.test.ts +20 -10
  39. package/src/execution/__tests__/helpers/fake-engine-port.ts +187 -0
  40. package/src/execution/__tests__/helpers/spawn-mock.ts +36 -9
  41. package/src/execution/__tests__/helpers/subagent-service-mocks.ts +1 -1
  42. package/src/execution/__tests__/idle-gc.test.ts +200 -0
  43. package/src/execution/__tests__/lifecycle-predicates.test.ts +26 -21
  44. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +5 -2
  45. package/src/execution/__tests__/reconcile-sweep.test.ts +200 -0
  46. package/src/execution/__tests__/record-store.test.ts +60 -6
  47. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +20 -13
  48. package/src/execution/__tests__/round-supervisor.test.ts +293 -0
  49. package/src/execution/__tests__/session-pending.test.ts +119 -17
  50. package/src/execution/__tests__/stream-sink-retirement.test.ts +10 -10
  51. package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +1 -11
  52. package/src/execution/__tests__/subagent-service-notify-gate.test.ts +33 -30
  53. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +2 -9
  54. package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +59 -129
  55. package/src/execution/__tests__/subagent-service.test.ts +2 -2
  56. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +109 -7
  57. package/src/execution/__tests__/subprocess-agent-runner.test.ts +108 -36
  58. package/src/execution/__tests__/sync-collect-recovery.test.ts +21 -36
  59. package/src/execution/__tests__/workflow-state-root.test.ts +232 -0
  60. package/src/execution/agent-registry.ts +6 -2
  61. package/src/execution/dialog-queue.ts +6 -73
  62. package/src/execution/engine/__tests__/common/capability-gate.test.ts +115 -15
  63. package/src/execution/engine/__tests__/common/errors.test.ts +11 -18
  64. package/src/execution/engine/__tests__/common/kill-chain.test.ts +7 -0
  65. package/src/execution/engine/__tests__/common/nesting-guard.test.ts +9 -3
  66. package/src/execution/engine/__tests__/common/session-view-service.test.ts +90 -3
  67. package/src/execution/engine/__tests__/conformance/H9-test-disposition.md +116 -0
  68. package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/fake-engine-protocol.mjs +377 -0
  69. package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/recorded.fixture.json +331 -0
  70. package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/smoke-run.fixture.json +213 -0
  71. package/src/execution/engine/__tests__/conformance/chat-round-protocol.test.ts +230 -0
  72. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +69 -42
  73. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +4 -81
  74. package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +67 -44
  75. package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +81 -54
  76. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +133 -70
  77. package/src/execution/engine/__tests__/conformance/engine-crash.test.ts +143 -0
  78. package/src/execution/engine/__tests__/conformance/fake-engine-capabilities.ts +19 -0
  79. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +7 -2
  80. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +6 -5
  81. package/src/execution/engine/__tests__/conformance/protocol-blackbox.test.ts +398 -0
  82. package/src/execution/engine/__tests__/conformance/registry-fork-filter.test.ts +221 -0
  83. package/src/execution/engine/__tests__/conformance/round-liveness-supervisor.test.ts +302 -0
  84. package/src/execution/engine/__tests__/conformance/static-spawn-guard.test.ts +58 -0
  85. package/src/execution/engine/__tests__/engine-discovery-scan.test.ts +558 -0
  86. package/src/execution/engine/__tests__/host-task-spec.test.ts +45 -0
  87. package/src/execution/engine/__tests__/model-ref-split.test.ts +74 -0
  88. package/src/execution/engine/__tests__/registry.test.ts +206 -1
  89. package/src/execution/engine/__tests__/routing.test.ts +97 -0
  90. package/src/execution/engine/__tests__/run-failure-worktree-cleanup.test.ts +97 -0
  91. package/src/execution/engine/client/__tests__/__fixtures__/fake-engine.mjs +294 -0
  92. package/src/execution/engine/client/__tests__/engine-client.test.ts +516 -0
  93. package/src/execution/engine/client/__tests__/mirror.test.ts +67 -0
  94. package/src/execution/engine/client/__tests__/pid-file.test.ts +257 -0
  95. package/src/execution/engine/client/__tests__/protocol-closure.test.ts +95 -0
  96. package/src/execution/engine/client/__tests__/remote-engine.test.ts +457 -0
  97. package/src/execution/engine/client/client-options.ts +103 -0
  98. package/src/execution/engine/client/engine-client.ts +687 -0
  99. package/src/execution/engine/client/mirror.ts +167 -0
  100. package/src/execution/engine/client/pid-file.ts +392 -0
  101. package/src/execution/engine/client/reaper.ts +95 -0
  102. package/src/execution/engine/client/remote-engine.ts +441 -0
  103. package/src/execution/engine/client/reverse-router.ts +255 -0
  104. package/src/execution/engine/common/capability-gate.ts +109 -22
  105. package/src/execution/engine/common/errors.ts +9 -25
  106. package/src/execution/engine/common/event-journal.ts +4 -50
  107. package/src/execution/engine/common/journal-replay.ts +3 -1
  108. package/src/execution/engine/common/kill-chain.ts +18 -251
  109. package/src/execution/engine/common/nesting-guard.ts +18 -114
  110. package/src/execution/engine/common/pool-manager.ts +4 -0
  111. package/src/execution/engine/common/session-view-service.ts +56 -84
  112. package/src/execution/engine/config.ts +151 -0
  113. package/src/execution/engine/d8-compat.ts +346 -0
  114. package/src/execution/engine/engine-discovery-roots.ts +107 -0
  115. package/src/execution/engine/engine-discovery-scan.ts +269 -0
  116. package/src/execution/engine/engine-discovery.ts +30 -7
  117. package/src/execution/engine/engine-inspect-package.ts +282 -0
  118. package/src/execution/engine/engine-manifest.ts +244 -0
  119. package/src/execution/engine/host/__tests__/host-askuser-endpoint.test.ts +123 -0
  120. package/src/execution/engine/host/__tests__/host-bridge.test.ts +135 -0
  121. package/src/execution/engine/host/__tests__/spawned-children.test.ts +73 -0
  122. package/src/execution/engine/host/host-bridge.ts +150 -0
  123. package/src/execution/engine/host/host-ui-endpoint.ts +47 -0
  124. package/src/execution/engine/host/pi-host-binding.ts +91 -0
  125. package/src/execution/engine/host/spawned-children.ts +139 -0
  126. package/src/execution/engine/host-task-spec.ts +29 -2
  127. package/src/execution/engine/model-validation.ts +55 -2
  128. package/src/execution/engine/paths.ts +16 -41
  129. package/src/execution/engine/port.ts +48 -2
  130. package/src/execution/engine/registry.ts +153 -34
  131. package/src/execution/engine/routing.ts +225 -52
  132. package/src/execution/engine/types.ts +25 -200
  133. package/src/execution/finalize-record.ts +25 -0
  134. package/src/execution/idle-gc.ts +89 -14
  135. package/src/execution/lifecycle-manager.ts +10 -7
  136. package/src/execution/lifecycle-predicates.ts +10 -8
  137. package/src/execution/record-store.ts +29 -2
  138. package/src/execution/relay-env.ts +19 -36
  139. package/src/execution/round-supervisor/domain.ts +89 -0
  140. package/src/execution/round-supervisor/index.ts +33 -0
  141. package/src/execution/round-supervisor/notify-accounting.ts +87 -0
  142. package/src/execution/round-supervisor/reconcile-sweep.ts +235 -0
  143. package/src/execution/round-supervisor/service-binding.test.ts +661 -0
  144. package/src/execution/round-supervisor/service-binding.ts +273 -0
  145. package/src/execution/round-supervisor/supervisor.ts +426 -0
  146. package/src/execution/session-pending.ts +68 -74
  147. package/src/execution/settled-watchdog.ts +39 -0
  148. package/src/execution/subagent-service.ts +746 -400
  149. package/src/execution/subprocess-agent-runner.ts +16 -8
  150. package/src/execution/types.ts +41 -117
  151. package/src/execution/ui-channels.ts +13 -214
  152. package/src/execution/ui-request-handler-factory.ts +7 -4
  153. package/src/execution/ui-request-observability.ts +2 -2
  154. package/src/execution/workflow-state-root.ts +67 -0
  155. package/src/execution/worktree-git-ops.ts +5 -0
  156. package/src/execution/worktree-manager.ts +11 -1
  157. package/src/index.ts +55 -26
  158. package/src/orchestration/__tests__/execute-agent-call.test.ts +1 -1
  159. package/src/orchestration/execute-agent-call.ts +1 -1
  160. package/src/orchestration/file-run-store.ts +144 -59
  161. package/src/orchestration/models/types.ts +43 -42
  162. package/src/shared/zcode-model-ref.ts +31 -0
  163. package/dist/chunk-43ONBFZX.js +0 -240
  164. package/dist/chunk-A4IVZWVX.js +0 -31
  165. package/dist/chunk-APZY4IME.js +0 -27
  166. package/dist/chunk-V3VHZ2VX.js +0 -59
  167. package/dist/execution/engine/engines/zcode/constants.cjs +0 -107
  168. package/dist/execution/engine/engines/zcode/constants.d.cts +0 -135
  169. package/dist/execution/engine/engines/zcode/constants.d.ts +0 -135
  170. package/dist/execution/engine/engines/zcode/constants.js +0 -54
  171. package/dist/execution/engine/engines/zcode/reader.cjs +0 -276
  172. package/dist/execution/engine/engines/zcode/reader.d.cts +0 -21
  173. package/dist/execution/engine/engines/zcode/reader.d.ts +0 -21
  174. package/dist/execution/engine/engines/zcode/reader.js +0 -9
  175. package/src/__tests__/append-system-prompt-assembly.test.ts +0 -243
  176. package/src/__tests__/fr4-get-state-handshake.test.ts +0 -125
  177. package/src/__tests__/session-runner.test.ts +0 -69
  178. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +0 -490
  179. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +0 -191
  180. package/src/execution/__tests__/descendant-sweep-guards.test.ts +0 -220
  181. package/src/execution/__tests__/descendant-sweep.test.ts +0 -269
  182. package/src/execution/__tests__/engine-model-validation.test.ts +0 -741
  183. package/src/execution/__tests__/epipe-fallback.test.ts +0 -248
  184. package/src/execution/__tests__/execution-runtime-face.test.ts +0 -272
  185. package/src/execution/__tests__/get-state-handshake.test.ts +0 -127
  186. package/src/execution/__tests__/helpers/session-runner-mocks.ts +0 -113
  187. package/src/execution/__tests__/keep-alive-no-progress.test.ts +0 -280
  188. package/src/execution/__tests__/kill-all-escalation.test.ts +0 -196
  189. package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +0 -113
  190. package/src/execution/__tests__/output-collector.test.ts +0 -469
  191. package/src/execution/__tests__/pi-invocation.test.ts +0 -166
  192. package/src/execution/__tests__/recursive-visibility-env.test.ts +0 -149
  193. package/src/execution/__tests__/rpc-mode.test.ts +0 -89
  194. package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +0 -387
  195. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +0 -277
  196. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +0 -254
  197. package/src/execution/__tests__/run-spawn-edges.test.ts +0 -1079
  198. package/src/execution/__tests__/run-spawn-integration.test.ts +0 -933
  199. package/src/execution/__tests__/run-spawn-resume.test.ts +0 -322
  200. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +0 -196
  201. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +0 -207
  202. package/src/execution/__tests__/service-kill-escalation.test.ts +0 -91
  203. package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +0 -110
  204. package/src/execution/__tests__/session-runner-close-prune.test.ts +0 -181
  205. package/src/execution/__tests__/session-runner-dispatch.test.ts +0 -489
  206. package/src/execution/__tests__/session-runner-epipe.test.ts +0 -179
  207. package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +0 -227
  208. package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +0 -290
  209. package/src/execution/__tests__/session-runner-schema-env.test.ts +0 -352
  210. package/src/execution/__tests__/settled-watchdog.test.ts +0 -524
  211. package/src/execution/__tests__/spawn-args.test.ts +0 -446
  212. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +0 -192
  213. package/src/execution/__tests__/spawn-event-adapter.test.ts +0 -167
  214. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +0 -208
  215. package/src/execution/__tests__/spawned-children.test.ts +0 -236
  216. package/src/execution/__tests__/start-sync-model-guard.test.ts +0 -150
  217. package/src/execution/__tests__/stdin-writer.test.ts +0 -464
  218. package/src/execution/__tests__/subagent-service-message-close.test.ts +0 -693
  219. package/src/execution/__tests__/temp-prompt.test.ts +0 -53
  220. package/src/execution/__tests__/timeout-integration.test.ts +0 -616
  221. package/src/execution/__tests__/turn-limiter-semantics.test.ts +0 -194
  222. package/src/execution/__tests__/turn-limiter.test.ts +0 -65
  223. package/src/execution/__tests__/ui-request-handler.test.ts +0 -205
  224. package/src/execution/__tests__/ui-request-queue.test.ts +0 -298
  225. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +0 -230
  226. package/src/execution/engine/__tests__/common/schema-emulation.test.ts +0 -128
  227. package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +0 -149
  228. package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +0 -28
  229. package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +0 -128
  230. package/src/execution/engine/__tests__/paths.test.ts +0 -39
  231. package/src/execution/engine/common/schema-emulation.ts +0 -189
  232. package/src/execution/engine/common/session-view-projection.ts +0 -51
  233. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +0 -615
  234. package/src/execution/engine/engines/pi/__tests__/reader.test.ts +0 -155
  235. package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +0 -257
  236. package/src/execution/engine/engines/pi/argv-mirror.ts +0 -135
  237. package/src/execution/engine/engines/pi/get-state-handshake.ts +0 -179
  238. package/src/execution/engine/engines/pi/output-collector.ts +0 -317
  239. package/src/execution/engine/engines/pi/pi-engine.ts +0 -811
  240. package/src/execution/engine/engines/pi/pi-invocation.ts +0 -120
  241. package/src/execution/engine/engines/pi/reader.ts +0 -59
  242. package/src/execution/engine/engines/pi/registration.ts +0 -37
  243. package/src/execution/engine/engines/pi/session-runner.ts +0 -2840
  244. package/src/execution/engine/engines/pi/spawn-event-adapter.ts +0 -404
  245. package/src/execution/engine/engines/pi/stdin-writer.ts +0 -199
  246. package/src/execution/engine/engines/pi/temp-prompt.ts +0 -62
  247. package/src/execution/engine/engines/pi/turn-limiter.ts +0 -102
  248. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +0 -301
  249. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-appserver.json +0 -36
  250. package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +0 -321
  251. package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +0 -473
  252. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +0 -43
  253. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +0 -124
  254. package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +0 -210
  255. package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +0 -71
  256. package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +0 -247
  257. package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +0 -451
  258. package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +0 -792
  259. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +0 -782
  260. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +0 -168
  261. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +0 -210
  262. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +0 -353
  263. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +0 -282
  264. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +0 -372
  265. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +0 -145
  266. package/src/execution/engine/engines/zcode/appserver-launcher.ts +0 -167
  267. package/src/execution/engine/engines/zcode/connection.ts +0 -598
  268. package/src/execution/engine/engines/zcode/constants.ts +0 -176
  269. package/src/execution/engine/engines/zcode/golden-sample.ts +0 -47
  270. package/src/execution/engine/engines/zcode/parser.ts +0 -102
  271. package/src/execution/engine/engines/zcode/preparer.ts +0 -235
  272. package/src/execution/engine/engines/zcode/reader.ts +0 -381
  273. package/src/execution/engine/engines/zcode/registration.ts +0 -37
  274. package/src/execution/engine/engines/zcode/session-channel.ts +0 -968
  275. package/src/execution/engine/engines/zcode/zcode-engine.ts +0 -1431
  276. package/src/execution/round-settlement.ts +0 -93
  277. package/src/execution/ui-request-queue.ts +0 -215
  278. package/src/shared/schema-env.ts +0 -44
@@ -0,0 +1,302 @@
1
+ // round-liveness-supervisor.test.ts —— [W6] 轮次活性监督器的 conformance 黑盒场景。
2
+ //
3
+ // 设计权威源:chat-domain-v1x-liveness-governance.md §3.2 D2(record 去向单一裁决
4
+ // 表 + 三态判定 + 通知对账 + 纳管模型)+ D5(H9 keep-alive-no-progress 承接落点)
5
+ // + 验收 A2/A5/A8。
6
+ //
7
+ // 与 W4 单测(execution/__tests__/round-supervisor.test.ts)的分工:W4 用替身 deps
8
+ // 全排列覆盖判定矩阵(白盒视角);本套件是**语义钉住层**——把设计裁决表的场景链
9
+ // (协议事件 → record 处置 → 监督动作)按黑盒视角钉成契约,只经公共出口
10
+ // (`round-supervisor/index.ts`)消费,不 import 内部符号。每条链对应一个真实验收
11
+ // 场景,替身 deps 是场景道具而非判定逻辑复制品:
12
+ //
13
+ // 场景一(表 3 行 1 全链,事故主链):run 在途 → 引擎进程被 SIGTERM(crash
14
+ // message 形态取自 engine-crash.test.ts 的协议实证)→ noteRunEnded +
15
+ // adoptOnProcessDeath → 合并单条通知 + 决策指引(该唤醒)→ 看门狗到期 →
16
+ // 该放弃(giveUp(watchdog-expired),此时可重派)。
17
+ // 场景二(裁决表 conversation 行):chatMode record 死亡事件 → 豁免不纳管
18
+ // (轮终 idle / settled-watchdog 管辖,D2 前置 1)。
19
+ // 场景三(表 3 行 2/3 × A5 落盘断言):boot 分区重认领(already-resumable-idle)
20
+ // vs conversation 豁免;in-flight 直断后的注册残留由对账 sweep **appendEntry
21
+ // 权威落盘**补发(A5「注销落盘可查」的构造性证据——sweep 写法钉死:不经 bus
22
+ // emit 作权威)。
23
+ // 场景四(通知对账两级启发式,R4):高置信替代 → 撤销指引改送终止通知 + 该放弃
24
+ // (superseded);低置信 → 指引自带豁免声明。
25
+ // 场景五(纳管模型:死亡事件纳管、重建不解管):crash 纳管后引擎被动重建
26
+ // (镜像重填)不解除纳管、不重发指引——判定只消费 record 级状态。
27
+ //
28
+ // timer 用 fake timers;监督器对 fs 零依赖(场景三的 session file 由 sweep 读侧
29
+ // 消费,mkdtempSync 自建自删)。
30
+
31
+ import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
32
+ import { tmpdir } from "node:os";
33
+ import { join } from "node:path";
34
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
35
+
36
+ import {
37
+ ROUND_SUPERVISOR_WATCHDOG_DEFAULT_MS,
38
+ RoundSupervisor,
39
+ runReconcileSweep,
40
+ type RoundSupervisorDeps,
41
+ type SupervisorCandidateRecord,
42
+ type SupervisorRecordView,
43
+ } from "../../../round-supervisor/index.ts";
44
+ import type { ExecutionRecord } from "../../../types.ts";
45
+
46
+ // ── 场景道具(替身 deps——黑盒观测面:通知/指引/替代/放弃四出口 + 三状态源)────
47
+
48
+ function makeDeps() {
49
+ const views = new Map<string, SupervisorRecordView>();
50
+ const candidates: SupervisorCandidateRecord[] = [];
51
+ const live = new Set<string>();
52
+ const notices: string[] = [];
53
+ const guidances: Array<{ record: SupervisorRecordView; exemptionDisclaimer: boolean }> = [];
54
+ const replaced: Array<{ record: SupervisorRecordView; replacementId: string }> = [];
55
+ const givenUp: Array<{ recordId: string; kind: string; detail: { replacementId?: string } }> = [];
56
+ const deps: RoundSupervisorDeps = {
57
+ now: () => Date.now(),
58
+ getRecordView: (id) => views.get(id),
59
+ listCandidateRecords: () => candidates,
60
+ hasLiveProcess: (recordId) => live.has(recordId),
61
+ sendMergedFailureNotice: (record) => notices.push(`merged:${record.id}`),
62
+ sendDecisionGuidance: (record, opts) =>
63
+ guidances.push({ record, exemptionDisclaimer: opts.exemptionDisclaimer }),
64
+ sendReplacedNotice: (record, replacementId) => replaced.push({ record, replacementId }),
65
+ giveUp: (recordId, kind, detail) => givenUp.push({ recordId, kind, detail }),
66
+ };
67
+ return Object.assign(deps, { views, candidates, live, notices, guidances, replaced, givenUp });
68
+ }
69
+
70
+ /** 后台子代理 record 替身(死亡事件纳管入口的入参形态)。 */
71
+ function makeRecord(overrides: Partial<ExecutionRecord> = {}): ExecutionRecord {
72
+ return {
73
+ id: "bg-1",
74
+ agent: "worker",
75
+ model: "m",
76
+ mode: "background",
77
+ task: "t",
78
+ slug: "fix-bug",
79
+ startedAt: Date.now() - 1000,
80
+ status: "running",
81
+ resumable: true,
82
+ rootSessionId: "sess-root",
83
+ turnCount: 0,
84
+ ...overrides,
85
+ } as ExecutionRecord;
86
+ }
87
+
88
+ function viewOf(record: ExecutionRecord, overrides: Partial<SupervisorRecordView> = {}): SupervisorRecordView {
89
+ return {
90
+ id: record.id,
91
+ status: record.status === "closed" ? "closed" : "running",
92
+ resumable: record.resumable === true,
93
+ hasResult: record.result !== undefined,
94
+ chatMode: record.chatMode === true,
95
+ rootSessionId: record.rootSessionId,
96
+ agent: record.agent,
97
+ slug: record.slug,
98
+ startedAt: record.startedAt,
99
+ closedReason: record.closedReason,
100
+ ...overrides,
101
+ };
102
+ }
103
+
104
+ /**
105
+ * 引擎进程信号死亡的真实错误 message 形态(engine-crash.test.ts 的协议实证——
106
+ * EngineClient.onEngineExit signal 分支 → engineCrashedError)。
107
+ */
108
+ const SIGTERM_CRASH_MESSAGE =
109
+ "engine_crashed: engine process exited unexpectedly: signal SIGTERM. stderr tail: (captured diagnostics)";
110
+
111
+ beforeEach(() => {
112
+ vi.useFakeTimers();
113
+ });
114
+
115
+ afterEach(() => {
116
+ vi.useRealTimers();
117
+ });
118
+
119
+ describe("[W6/D2 表 3 行 1] 引擎死亡 → failed 如实 + 监督器接管(事故主链)", () => {
120
+ it("run 在途 → SIGTERM crash → 纳管:合并单条通知 + 决策指引(该唤醒)→ 看门狗到期 giveUp(该放弃)", async () => {
121
+ const deps = makeDeps();
122
+ const supervisor = new RoundSupervisor(deps);
123
+ const record = makeRecord();
124
+ deps.views.set(record.id, viewOf(record));
125
+
126
+ // 该等:run 在途(协议 run 帧受理——noteRunStarted 记账)→ 死亡事件前不干预。
127
+ supervisor.noteRunStarted(record.id);
128
+
129
+ // 死亡事件:run 终态 failed(engine_crashed,SIGTERM 形态)→ 驱动记账解除 +
130
+ // record 保持 resumable(subagent-service adoptResumableAfterEngineDeath 的
131
+ // 生产序列)→ 监督器纳管。
132
+ supervisor.noteRunEnded(record.id);
133
+ supervisor.adoptOnProcessDeath(record, SIGTERM_CRASH_MESSAGE);
134
+
135
+ // 表 3 行 1 通知契约:failed 如实 + 已接管契约合并为**单条**通知(无双通知
136
+ // 时序窗口);主 agent 是唯一决策者——监督器不自动复活,只送决策指引。
137
+ expect(deps.notices).toEqual([`merged:${record.id}`]);
138
+ expect(deps.guidances).toHaveLength(1);
139
+ expect(deps.guidances[0].exemptionDisclaimer).toBe(false);
140
+ expect(supervisor.supervisedIds()).toEqual([record.id]);
141
+
142
+ // 该唤醒后的等待有主:决策看门狗 armed(默认 2h)——到期且无决策/无收敛 →
143
+ // 该放弃(failed 终态化 + 注销 + 终止通知,此时可重派)。
144
+ await vi.advanceTimersByTimeAsync(ROUND_SUPERVISOR_WATCHDOG_DEFAULT_MS + 1);
145
+ expect(deps.givenUp).toEqual([{ recordId: record.id, kind: "watchdog-expired", detail: {} }]);
146
+ expect(supervisor.supervisedIds()).toEqual([]);
147
+ });
148
+
149
+ it("死亡事件重复(二次 crash 事件)幂等:不重复通知、不重复指引", () => {
150
+ const deps = makeDeps();
151
+ const supervisor = new RoundSupervisor(deps);
152
+ const record = makeRecord();
153
+ deps.views.set(record.id, viewOf(record));
154
+ supervisor.adoptOnProcessDeath(record, SIGTERM_CRASH_MESSAGE);
155
+ supervisor.adoptOnProcessDeath(record, SIGTERM_CRASH_MESSAGE);
156
+ expect(deps.notices).toHaveLength(1);
157
+ expect(deps.guidances).toHaveLength(1);
158
+ });
159
+ });
160
+
161
+ describe("[W6/D2 裁决表 conversation 行] chat 域豁免", () => {
162
+ it("chatMode record 的死亡事件不入监督域(轮终 idle / settled-watchdog 管辖)", () => {
163
+ const deps = makeDeps();
164
+ const supervisor = new RoundSupervisor(deps);
165
+ supervisor.adoptOnProcessDeath(makeRecord({ chatMode: true, resumable: true }), SIGTERM_CRASH_MESSAGE);
166
+ expect(deps.notices).toHaveLength(0);
167
+ expect(deps.guidances).toHaveLength(0);
168
+ expect(supervisor.supervisedIds()).toEqual([]);
169
+ });
170
+ });
171
+
172
+ describe("[W6/D2 表 3 行 2/3 × A5] boot 分区与 sweep 落盘衔接", () => {
173
+ it("already-resumable-idle(非 conversation)→ 重认领接管并送达指引", () => {
174
+ const deps = makeDeps();
175
+ const supervisor = new RoundSupervisor(deps);
176
+ const record = makeRecord({ id: "bg-survivor" });
177
+ deps.candidates.push({ id: record.id, rootSessionId: record.rootSessionId, agent: record.agent, slug: record.slug, startedAt: record.startedAt });
178
+ deps.views.set(record.id, viewOf(record));
179
+ const { readopted } = supervisor.bootPartition();
180
+ expect(readopted).toEqual([record.id]);
181
+ expect(deps.guidances).toHaveLength(1);
182
+ expect(supervisor.supervisedIds()).toEqual([record.id]);
183
+ });
184
+
185
+ it("in-flight 直断后的注册残留 → 对账 sweep appendEntry 权威落盘(A5「注销落盘可查」)", () => {
186
+ const dir = mkdtempSync(join(tmpdir(), "w6-supervisor-sweep-"));
187
+ try {
188
+ const sessionFile = join(dir, "session-child.jsonl");
189
+ // 子 session 文件里的 register 残留(进程死亡窗口内注销发射源已消失——
190
+ // notify-host getPi() 为 null 的缺位形态)。
191
+ writeFileSync(
192
+ sessionFile,
193
+ `${JSON.stringify({ customType: "pending:register", data: { id: "bg-inflight", type: "subagent", name: "worker", sessionId: "sess-root" } })}\n`,
194
+ "utf8",
195
+ );
196
+ const appended: Array<{ customType: string; data: unknown }> = [];
197
+ const result = runReconcileSweep({
198
+ sessionFile,
199
+ lookupRecordState: (id) =>
200
+ id === "bg-inflight" ? { terminal: true, closedReason: "boot-abort" } : "active",
201
+ appendEntry: (customType, data) => {
202
+ appended.push({ customType, data });
203
+ // 权威落盘 = 直接 appendEntry(写法钉死:不经 bus emit 作权威)——
204
+ // 用真实文件追加复现「落盘可查」。
205
+ writeFileSync(
206
+ sessionFile,
207
+ `${JSON.stringify({ customType, data })}\n`,
208
+ { flag: "a" },
209
+ );
210
+ },
211
+ });
212
+ expect(result.reconciled).toEqual(["bg-inflight"]);
213
+ expect(appended).toHaveLength(1);
214
+ expect(appended[0].customType).toBe("pending:unregister");
215
+ // 差集消费方(goal 守卫)从持久化 entries 算差集——文件里补发的 unregister
216
+ // 对守卫直接生效(守卫计数归零,A5 断言「重开后守卫计数归零」)。
217
+ const lines = readFileSync(sessionFile, "utf8").trim().split("\n").map((l) => JSON.parse(l));
218
+ expect(lines.some((l) => l.customType === "pending:unregister" && l.data.id === "bg-inflight")).toBe(true);
219
+ } finally {
220
+ rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
221
+ }
222
+ });
223
+
224
+ it("sweep 保守性:record 仍活跃的注册跳过(不误注销活跃后台任务)", () => {
225
+ const dir = mkdtempSync(join(tmpdir(), "w6-supervisor-sweep-active-"));
226
+ try {
227
+ const sessionFile = join(dir, "session-child.jsonl");
228
+ writeFileSync(
229
+ sessionFile,
230
+ `${JSON.stringify({ customType: "pending:register", data: { id: "bg-alive", type: "subagent", name: "worker", sessionId: "sess-root" } })}\n`,
231
+ "utf8",
232
+ );
233
+ const result = runReconcileSweep({
234
+ sessionFile,
235
+ lookupRecordState: () => "active",
236
+ });
237
+ expect(result.reconciled).toEqual([]);
238
+ expect(result.skippedActive).toEqual(["bg-alive"]);
239
+ } finally {
240
+ rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
241
+ }
242
+ });
243
+ });
244
+
245
+ describe("[W6/D2 通知对账(R4 两级启发式)]", () => {
246
+ it("高置信替代(同 root + 同 agent + 同 slug + 窗内)→ 撤销指引改送终止通知 + 该放弃(superseded)", () => {
247
+ const deps = makeDeps();
248
+ const supervisor = new RoundSupervisor(deps);
249
+ const record = makeRecord();
250
+ deps.views.set(record.id, viewOf(record));
251
+ // 主 agent 在指引送达前已重派同任务(唯一决策者,重派合法)。
252
+ deps.candidates.push({ id: "bg-2", rootSessionId: "sess-root", agent: "worker", slug: "fix-bug", startedAt: Date.now() - 1000 });
253
+
254
+ supervisor.adoptOnProcessDeath(record, SIGTERM_CRASH_MESSAGE);
255
+
256
+ expect(deps.guidances).toHaveLength(0); // 指引撤销(无双执行残径)
257
+ expect(deps.replaced).toHaveLength(1);
258
+ expect(deps.replaced[0].replacementId).toBe("bg-2");
259
+ expect(deps.givenUp).toEqual([{ recordId: record.id, kind: "superseded", detail: { replacementId: "bg-2" } }]);
260
+ expect(supervisor.supervisedIds()).toEqual([]);
261
+ });
262
+
263
+ it("低置信(仅 agent 同名)→ 不撤销指引,指引自带豁免声明(残余决策交还主 agent)", () => {
264
+ const deps = makeDeps();
265
+ const supervisor = new RoundSupervisor(deps);
266
+ const record = makeRecord();
267
+ deps.views.set(record.id, viewOf(record));
268
+ deps.candidates.push({ id: "bg-2", rootSessionId: "sess-root", agent: "worker", slug: "other-task", startedAt: Date.now() - 1000 });
269
+
270
+ supervisor.adoptOnProcessDeath(record, SIGTERM_CRASH_MESSAGE);
271
+
272
+ expect(deps.guidances).toHaveLength(1);
273
+ expect(deps.guidances[0].exemptionDisclaimer).toBe(true);
274
+ expect(deps.givenUp).toHaveLength(0);
275
+ });
276
+ });
277
+
278
+ describe("[W6/D2 纳管模型] 死亡事件纳管、重建不解管", () => {
279
+ it("crash 纳管后引擎被动重建(镜像重填再置死)不解除纳管、不重发指引", async () => {
280
+ const deps = makeDeps();
281
+ const supervisor = new RoundSupervisor(deps);
282
+ const record = makeRecord();
283
+ deps.views.set(record.id, viewOf(record));
284
+
285
+ supervisor.adoptOnProcessDeath(record, SIGTERM_CRASH_MESSAGE);
286
+ expect(deps.guidances).toHaveLength(1);
287
+
288
+ // 引擎被动重建(ensureConnected 退避重填镜像——任一会话的下个请求触发):
289
+ // 镜像判「该等」仅解除看门狗计时;record 级状态未变 → 纳管持续、指引不重发。
290
+ deps.live.add(record.id);
291
+ supervisor.noteRunEnded(record.id);
292
+ expect(supervisor.supervisedIds()).toEqual([record.id]);
293
+ expect(deps.guidances).toHaveLength(1);
294
+
295
+ // 重建后的进程又死(镜像再置死)——判定仍只消费 record 级状态。
296
+ deps.live.delete(record.id);
297
+ supervisor.noteRunEnded(record.id);
298
+ expect(supervisor.supervisedIds()).toEqual([record.id]);
299
+ expect(deps.guidances).toHaveLength(1);
300
+ expect(deps.givenUp).toHaveLength(0);
301
+ });
302
+ });
@@ -0,0 +1,58 @@
1
+ // static-spawn-guard.test.ts —— W10 静态断言「任务子进程 spawn 必经 SDK
2
+ // spawnEngineChild」的 CI 挂载点(vitest 内执行 scripts/check-engine-spawn-guard.mjs,
3
+ // 不依赖 W9 的 workflows 领地;进 CI invariants job 的落点与 W9 协调——本地经本
4
+ // 测试即恒绿门)。
5
+ //
6
+ // 正例:两引擎包 src 干净 + 存在 spawnEngineChild 消费点(防空转)。
7
+ // 负例:临时 root 内放置直接 spawn 的源文件 → 脚本必须红(守卫有牙,A12 同款
8
+ // 负例自证)。
9
+ //
10
+ // 与 C-proc-09(check_spawn_env_boundary.py)分工互不代偿:C-proc-09 盖 spawn 点
11
+ // env 出站卫生(全仓),本守卫盖引擎包 spawn 单一入口(形态 + stdin fd 不外泄)。
12
+
13
+ import { execFile } from "node:child_process";
14
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
15
+ import { tmpdir } from "node:os";
16
+ import { dirname, join } from "node:path";
17
+ import { fileURLToPath } from "node:url";
18
+ import { promisify } from "node:util";
19
+ import { afterEach, describe, expect, it } from "vitest";
20
+
21
+ const execFileAsync = promisify(execFile);
22
+ const GUARD = join(
23
+ dirname(fileURLToPath(import.meta.url)),
24
+ "../../../../../scripts/check-engine-spawn-guard.mjs",
25
+ );
26
+
27
+ let tmpRoots: string[] = [];
28
+
29
+ afterEach(() => {
30
+ for (const root of tmpRoots) rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
31
+ tmpRoots = [];
32
+ });
33
+
34
+ describe("静态断言:引擎包任务子进程必经 spawnEngineChild", () => {
35
+ it("正例:两引擎包 src 干净且存在 spawnEngineChild 消费点", async () => {
36
+ const { stdout } = await execFileAsync("node", [GUARD]);
37
+ expect(stdout).toContain("[engine-spawn-guard] PASS");
38
+ expect(stdout).toMatch(/spawnEngineChild/);
39
+ });
40
+
41
+ it("负例:直接 spawn 的源文件必须被检出(守卫有牙)", async () => {
42
+ const root = mkdtempSync(join(tmpdir(), "spawn-guard-neg-"));
43
+ tmpRoots.push(root);
44
+ mkdirSync(join(root, "__tests__"), { recursive: true });
45
+ // __tests__ 排除面(测试文件可用 child_process mock)——放一个不触发的样本
46
+ writeFileSync(join(root, "__tests__", "mock.test.ts"), 'import { spawn } from "node:child_process";\n');
47
+ // src 直陈违规:直接 spawn(未走 SDK spawnEngineChild)
48
+ mkdirSync(join(root, "engine"), { recursive: true });
49
+ writeFileSync(
50
+ join(root, "engine", "bypass.ts"),
51
+ 'import { spawn } from "node:child_process";\nexport const p = spawn("ls");\n',
52
+ );
53
+ await expect(execFileAsync("node", [GUARD, "--roots", root])).rejects.toMatchObject({
54
+ code: 1,
55
+ stderr: expect.stringContaining("spawn"),
56
+ });
57
+ });
58
+ });