sdd-agent-platform 0.4.1 → 0.5.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 (698) hide show
  1. package/README.md +24 -28
  2. package/node_modules/@sdd-agent-platform/core/dist/ai-tools.js +84 -103
  3. package/node_modules/@sdd-agent-platform/core/dist/ai-tools.js.map +1 -1
  4. package/node_modules/@sdd-agent-platform/core/dist/config/init-project.d.ts +10 -6
  5. package/node_modules/@sdd-agent-platform/core/dist/config/init-project.js +7 -8
  6. package/node_modules/@sdd-agent-platform/core/dist/config/init-project.js.map +1 -1
  7. package/node_modules/@sdd-agent-platform/core/dist/config/project-config.d.ts +3 -1
  8. package/node_modules/@sdd-agent-platform/core/dist/config/project-config.js +7 -3
  9. package/node_modules/@sdd-agent-platform/core/dist/config/project-config.js.map +1 -1
  10. package/node_modules/@sdd-agent-platform/core/dist/config/starter-documents.d.ts +0 -1
  11. package/node_modules/@sdd-agent-platform/core/dist/config/starter-documents.js +374 -421
  12. package/node_modules/@sdd-agent-platform/core/dist/config/starter-documents.js.map +1 -1
  13. package/node_modules/@sdd-agent-platform/core/dist/context/build-package.d.ts +1 -1
  14. package/node_modules/@sdd-agent-platform/core/dist/context/build-package.js +7 -19
  15. package/node_modules/@sdd-agent-platform/core/dist/context/build-package.js.map +1 -1
  16. package/node_modules/@sdd-agent-platform/core/dist/contracts.d.ts +7 -1
  17. package/node_modules/@sdd-agent-platform/core/dist/contracts.js +6 -0
  18. package/node_modules/@sdd-agent-platform/core/dist/contracts.js.map +1 -1
  19. package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/document-chain.js +2 -12
  20. package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/document-chain.js.map +1 -1
  21. package/node_modules/@sdd-agent-platform/core/dist/doctor/doctor.js +1 -18
  22. package/node_modules/@sdd-agent-platform/core/dist/doctor/doctor.js.map +1 -1
  23. package/node_modules/@sdd-agent-platform/core/dist/evidence/lookup.d.ts +1 -1
  24. package/node_modules/@sdd-agent-platform/core/dist/evidence/lookup.js +1 -1
  25. package/node_modules/@sdd-agent-platform/core/dist/evidence/lookup.js.map +1 -1
  26. package/node_modules/@sdd-agent-platform/core/dist/evidence-runtime/contracts.d.ts +0 -1
  27. package/node_modules/@sdd-agent-platform/core/dist/evidence-runtime/coordination.js +110 -0
  28. package/node_modules/@sdd-agent-platform/core/dist/evidence-runtime/coordination.js.map +1 -0
  29. package/node_modules/@sdd-agent-platform/core/dist/execution/host-invocation.js +83 -83
  30. package/node_modules/@sdd-agent-platform/core/dist/instructions.d.ts +1 -1
  31. package/node_modules/@sdd-agent-platform/core/dist/instructions.js +37 -80
  32. package/node_modules/@sdd-agent-platform/core/dist/instructions.js.map +1 -1
  33. package/node_modules/@sdd-agent-platform/core/dist/lifecycle/ship.js +58 -68
  34. package/node_modules/@sdd-agent-platform/core/dist/lifecycle/ship.js.map +1 -1
  35. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/contracts.d.ts +159 -0
  36. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/contracts.js +7 -0
  37. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/contracts.js.map +1 -0
  38. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/kernel.d.ts +16 -0
  39. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/kernel.js +461 -0
  40. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/kernel.js.map +1 -0
  41. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph.d.ts +2 -0
  42. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph.js +3 -0
  43. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph.js.map +1 -0
  44. package/node_modules/@sdd-agent-platform/core/dist/orchestration/contracts.d.ts +1 -1
  45. package/node_modules/@sdd-agent-platform/core/dist/orchestration/runtime.js +21 -28
  46. package/node_modules/@sdd-agent-platform/core/dist/orchestration/runtime.js.map +1 -1
  47. package/node_modules/@sdd-agent-platform/core/dist/registries/agent-registry.js +124 -40
  48. package/node_modules/@sdd-agent-platform/core/dist/registries/agent-registry.js.map +1 -1
  49. package/node_modules/@sdd-agent-platform/core/dist/registries/command-team-runtime.d.ts +1 -1
  50. package/node_modules/@sdd-agent-platform/core/dist/registries/command-team-runtime.js +6 -13
  51. package/node_modules/@sdd-agent-platform/core/dist/registries/command-team-runtime.js.map +1 -1
  52. package/node_modules/@sdd-agent-platform/core/dist/registries/plan-scout-domains.d.ts +13 -0
  53. package/node_modules/@sdd-agent-platform/core/dist/registries/plan-scout-domains.js +76 -0
  54. package/node_modules/@sdd-agent-platform/core/dist/registries/plan-scout-domains.js.map +1 -0
  55. package/node_modules/@sdd-agent-platform/core/dist/registries/skill-capabilities.js +7 -7
  56. package/node_modules/@sdd-agent-platform/core/dist/registries/skill-capabilities.js.map +1 -1
  57. package/node_modules/@sdd-agent-platform/core/dist/registries/tool-capabilities.js +6 -6
  58. package/node_modules/@sdd-agent-platform/core/dist/registries/tool-capabilities.js.map +1 -1
  59. package/node_modules/@sdd-agent-platform/core/dist/registries/workflow-gates.d.ts +1 -1
  60. package/node_modules/@sdd-agent-platform/core/dist/registries/workflow-gates.js +18 -18
  61. package/node_modules/@sdd-agent-platform/core/dist/registries/workflow-gates.js.map +1 -1
  62. package/node_modules/@sdd-agent-platform/core/dist/risk/consumer-diagnostics.js +2 -1
  63. package/node_modules/@sdd-agent-platform/core/dist/risk/consumer-diagnostics.js.map +1 -1
  64. package/node_modules/@sdd-agent-platform/core/dist/risk/contracts.d.ts +2 -2
  65. package/node_modules/@sdd-agent-platform/core/dist/risk/kernel.js +7 -7
  66. package/node_modules/@sdd-agent-platform/core/dist/risk/kernel.js.map +1 -1
  67. package/node_modules/@sdd-agent-platform/core/dist/risk/legacy-adapters.js +12 -27
  68. package/node_modules/@sdd-agent-platform/core/dist/risk/legacy-adapters.js.map +1 -1
  69. package/node_modules/@sdd-agent-platform/core/dist/risk/workflow-gates.js +6 -6
  70. package/node_modules/@sdd-agent-platform/core/dist/risk/workflow-gates.js.map +1 -1
  71. package/node_modules/@sdd-agent-platform/core/dist/router/agent-runtime-config.js +1 -1
  72. package/node_modules/@sdd-agent-platform/core/dist/router/agent-runtime-config.js.map +1 -1
  73. package/node_modules/@sdd-agent-platform/core/dist/router/routing.js +2 -4
  74. package/node_modules/@sdd-agent-platform/core/dist/router/routing.js.map +1 -1
  75. package/node_modules/@sdd-agent-platform/core/dist/router/runtime-import.d.ts +28 -0
  76. package/node_modules/@sdd-agent-platform/core/dist/router/runtime-import.js +383 -0
  77. package/node_modules/@sdd-agent-platform/core/dist/router/runtime-import.js.map +1 -0
  78. package/node_modules/@sdd-agent-platform/core/dist/router/stage-route-binding.d.ts +37 -0
  79. package/node_modules/@sdd-agent-platform/core/dist/router/stage-route-binding.js +227 -0
  80. package/node_modules/@sdd-agent-platform/core/dist/router/stage-route-binding.js.map +1 -0
  81. package/node_modules/@sdd-agent-platform/core/dist/router.d.ts +1 -0
  82. package/node_modules/@sdd-agent-platform/core/dist/router.js +1 -0
  83. package/node_modules/@sdd-agent-platform/core/dist/router.js.map +1 -1
  84. package/node_modules/@sdd-agent-platform/core/dist/run-state/artifacts.d.ts +16 -0
  85. package/node_modules/@sdd-agent-platform/core/dist/run-state/artifacts.js +6 -0
  86. package/node_modules/@sdd-agent-platform/core/dist/run-state/artifacts.js.map +1 -1
  87. package/node_modules/@sdd-agent-platform/core/dist/run-state/model.d.ts +20 -0
  88. package/node_modules/@sdd-agent-platform/core/dist/run-state/run-state.js +7 -7
  89. package/node_modules/@sdd-agent-platform/core/dist/run-state/run-state.js.map +1 -1
  90. package/node_modules/@sdd-agent-platform/core/dist/run-state/task-evidence.d.ts +1 -2
  91. package/node_modules/@sdd-agent-platform/core/dist/run-state/task-evidence.js +2 -9
  92. package/node_modules/@sdd-agent-platform/core/dist/run-state/task-evidence.js.map +1 -1
  93. package/node_modules/@sdd-agent-platform/core/dist/run-state/timing.d.ts +8 -0
  94. package/node_modules/@sdd-agent-platform/core/dist/run-state/timing.js +131 -0
  95. package/node_modules/@sdd-agent-platform/core/dist/run-state/timing.js.map +1 -0
  96. package/node_modules/@sdd-agent-platform/core/dist/runtime-analysis/build.js +1 -4
  97. package/node_modules/@sdd-agent-platform/core/dist/runtime-analysis/build.js.map +1 -1
  98. package/node_modules/@sdd-agent-platform/core/dist/runtime-analysis/findings.js +0 -39
  99. package/node_modules/@sdd-agent-platform/core/dist/runtime-analysis/findings.js.map +1 -1
  100. package/node_modules/@sdd-agent-platform/core/dist/runtime-analysis/model.d.ts +1 -17
  101. package/node_modules/@sdd-agent-platform/core/dist/runtime-paths.d.ts +10 -0
  102. package/node_modules/@sdd-agent-platform/core/dist/runtime-paths.js +65 -0
  103. package/node_modules/@sdd-agent-platform/core/dist/runtime-paths.js.map +1 -1
  104. package/node_modules/@sdd-agent-platform/core/dist/runtime-projection-p0.d.ts +64 -0
  105. package/node_modules/@sdd-agent-platform/core/dist/runtime-projection-p0.js +211 -0
  106. package/node_modules/@sdd-agent-platform/core/dist/runtime-projection-p0.js.map +1 -0
  107. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/artifact-depth.d.ts +14 -0
  108. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/artifact-depth.js +179 -0
  109. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/artifact-depth.js.map +1 -0
  110. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-parser.d.ts +5 -1
  111. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-parser.js +60 -22
  112. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-parser.js.map +1 -1
  113. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-rendering.js +2 -2
  114. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-rendering.js.map +1 -1
  115. package/node_modules/@sdd-agent-platform/core/dist/spec-entry.js +40 -0
  116. package/node_modules/@sdd-agent-platform/core/dist/spec-entry.js.map +1 -0
  117. package/node_modules/@sdd-agent-platform/core/dist/spec-manager-contracts.d.ts +12 -0
  118. package/node_modules/@sdd-agent-platform/core/dist/spec-manager-contracts.js +2 -0
  119. package/node_modules/@sdd-agent-platform/core/dist/spec-manager-contracts.js.map +1 -0
  120. package/node_modules/@sdd-agent-platform/core/dist/stage-artifacts.d.ts +55 -0
  121. package/node_modules/@sdd-agent-platform/core/dist/stage-artifacts.js +315 -0
  122. package/node_modules/@sdd-agent-platform/core/dist/stage-artifacts.js.map +1 -0
  123. package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration-contracts.d.ts +55 -0
  124. package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration-contracts.js +238 -0
  125. package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration-contracts.js.map +1 -0
  126. package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration.d.ts +736 -0
  127. package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration.js +4018 -0
  128. package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration.js.map +1 -0
  129. package/node_modules/@sdd-agent-platform/core/dist/stage-runtime/runtime.js +8 -1
  130. package/node_modules/@sdd-agent-platform/core/dist/stage-runtime/runtime.js.map +1 -1
  131. package/node_modules/@sdd-agent-platform/core/dist/status/project-status.js +25 -1
  132. package/node_modules/@sdd-agent-platform/core/dist/status/project-status.js.map +1 -1
  133. package/node_modules/@sdd-agent-platform/core/dist/storage/runtime-store.d.ts +170 -18
  134. package/node_modules/@sdd-agent-platform/core/dist/storage/runtime-store.js +597 -85
  135. package/node_modules/@sdd-agent-platform/core/dist/storage/runtime-store.js.map +1 -1
  136. package/node_modules/@sdd-agent-platform/core/dist/sync-back/apply.d.ts +1 -17
  137. package/node_modules/@sdd-agent-platform/core/dist/sync-back/apply.js +1 -242
  138. package/node_modules/@sdd-agent-platform/core/dist/sync-back/apply.js.map +1 -1
  139. package/node_modules/@sdd-agent-platform/core/dist/sync-back/inspect.d.ts +1 -110
  140. package/node_modules/@sdd-agent-platform/core/dist/sync-back/inspect.js +1 -496
  141. package/node_modules/@sdd-agent-platform/core/dist/sync-back/inspect.js.map +1 -1
  142. package/node_modules/@sdd-agent-platform/core/dist/sync-back.d.ts +1 -2
  143. package/node_modules/@sdd-agent-platform/core/dist/sync-back.js +1 -2
  144. package/node_modules/@sdd-agent-platform/core/dist/sync-back.js.map +1 -1
  145. package/node_modules/@sdd-agent-platform/core/dist/task-execution-contract.d.ts +167 -0
  146. package/node_modules/@sdd-agent-platform/core/dist/task-execution-contract.js +377 -0
  147. package/node_modules/@sdd-agent-platform/core/dist/task-execution-contract.js.map +1 -0
  148. package/node_modules/@sdd-agent-platform/core/dist/test-support/fixtures.js +329 -314
  149. package/node_modules/@sdd-agent-platform/core/dist/test-support/fixtures.js.map +1 -1
  150. package/node_modules/@sdd-agent-platform/core/dist/test-support/run-state.d.ts +1 -0
  151. package/node_modules/@sdd-agent-platform/core/dist/test-support/run-state.js +31 -0
  152. package/node_modules/@sdd-agent-platform/core/dist/test-support/run-state.js.map +1 -1
  153. package/node_modules/@sdd-agent-platform/core/dist/truth-reconciliation.d.ts +44 -0
  154. package/node_modules/@sdd-agent-platform/core/dist/truth-reconciliation.js +135 -0
  155. package/node_modules/@sdd-agent-platform/core/dist/truth-reconciliation.js.map +1 -0
  156. package/node_modules/@sdd-agent-platform/core/dist/tsconfig.tsbuildinfo +1 -1
  157. package/node_modules/@sdd-agent-platform/core/dist/verification/goal-verify.d.ts +0 -49
  158. package/node_modules/@sdd-agent-platform/core/dist/verification/goal-verify.js +1 -545
  159. package/node_modules/@sdd-agent-platform/core/dist/verification/goal-verify.js.map +1 -1
  160. package/node_modules/@sdd-agent-platform/core/dist/verification/rendering.d.ts +5 -7
  161. package/node_modules/@sdd-agent-platform/core/dist/verification/rendering.js +15 -55
  162. package/node_modules/@sdd-agent-platform/core/dist/verification/rendering.js.map +1 -1
  163. package/node_modules/@sdd-agent-platform/core/dist/verification/single-task-loop.js +1 -40
  164. package/node_modules/@sdd-agent-platform/core/dist/verification/single-task-loop.js.map +1 -1
  165. package/node_modules/@sdd-agent-platform/core/dist/verification/task-evidence-judgment.d.ts +49 -0
  166. package/node_modules/@sdd-agent-platform/core/dist/verification/task-evidence-judgment.js +521 -0
  167. package/node_modules/@sdd-agent-platform/core/dist/verification/task-evidence-judgment.js.map +1 -0
  168. package/node_modules/@sdd-agent-platform/core/dist/verification/test-runtime.d.ts +12 -2
  169. package/node_modules/@sdd-agent-platform/core/dist/verification/test-runtime.js +247 -112
  170. package/node_modules/@sdd-agent-platform/core/dist/verification/test-runtime.js.map +1 -1
  171. package/node_modules/@sdd-agent-platform/core/dist/verification/validation-cache.d.ts +26 -0
  172. package/node_modules/@sdd-agent-platform/core/dist/verification/validation-cache.js +73 -0
  173. package/node_modules/@sdd-agent-platform/core/dist/verification/validation-cache.js.map +1 -0
  174. package/node_modules/@sdd-agent-platform/core/dist/verification/verify-contract.d.ts +1 -1
  175. package/node_modules/@sdd-agent-platform/core/dist/verification/verify-contract.js +49 -72
  176. package/node_modules/@sdd-agent-platform/core/dist/verification/verify-contract.js.map +1 -1
  177. package/node_modules/@sdd-agent-platform/core/dist/verification.d.ts +3 -3
  178. package/node_modules/@sdd-agent-platform/core/dist/verification.js +2 -2
  179. package/node_modules/@sdd-agent-platform/core/dist/verification.js.map +1 -1
  180. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/evidence-packet.js +2 -7
  181. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/evidence-packet.js.map +1 -1
  182. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/hard-checks.js +0 -7
  183. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/hard-checks.js.map +1 -1
  184. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/policy.js +2 -4
  185. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/policy.js.map +1 -1
  186. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/types.d.ts +3 -5
  187. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/latest-eligible-run.js +30 -4
  188. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/latest-eligible-run.js.map +1 -1
  189. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/migration-recovery.d.ts +40 -0
  190. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/migration-recovery.js +110 -0
  191. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/migration-recovery.js.map +1 -0
  192. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/repair-contract.d.ts +12 -0
  193. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/repair-contract.js +63 -0
  194. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/repair-contract.js.map +1 -0
  195. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/resolve-task-run.d.ts +21 -0
  196. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/resolve-task-run.js +95 -0
  197. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/resolve-task-run.js.map +1 -0
  198. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/resolve.d.ts +55 -5
  199. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/resolve.js +518 -36
  200. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/resolve.js.map +1 -1
  201. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/runtime-projections.d.ts +228 -0
  202. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/runtime-projections.js +452 -0
  203. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/runtime-projections.js.map +1 -0
  204. package/node_modules/@sdd-agent-platform/core/package.json +6 -3
  205. package/node_modules/@sdd-agent-platform/core/src/ai-tools.test.ts +238 -137
  206. package/node_modules/@sdd-agent-platform/core/src/ai-tools.ts +84 -103
  207. package/node_modules/@sdd-agent-platform/core/src/artifacts/ingestion.test.ts +189 -189
  208. package/node_modules/@sdd-agent-platform/core/src/artifacts/ingestion.ts +222 -222
  209. package/node_modules/@sdd-agent-platform/core/src/artifacts/sdd-evidence.test.ts +28 -28
  210. package/node_modules/@sdd-agent-platform/core/src/artifacts/sdd-evidence.ts +302 -302
  211. package/node_modules/@sdd-agent-platform/core/src/artifacts/sdd-result.test.ts +181 -181
  212. package/node_modules/@sdd-agent-platform/core/src/artifacts/sdd-result.ts +231 -231
  213. package/node_modules/@sdd-agent-platform/core/src/artifacts/templates.ts +99 -99
  214. package/node_modules/@sdd-agent-platform/core/src/artifacts.ts +4 -4
  215. package/node_modules/@sdd-agent-platform/core/src/coding-facts/contracts.ts +79 -79
  216. package/node_modules/@sdd-agent-platform/core/src/coding-facts.ts +1 -1
  217. package/node_modules/@sdd-agent-platform/core/src/config/init-project.test.ts +314 -306
  218. package/node_modules/@sdd-agent-platform/core/src/config/init-project.ts +128 -120
  219. package/node_modules/@sdd-agent-platform/core/src/config/project-config.ts +265 -259
  220. package/node_modules/@sdd-agent-platform/core/src/config/project-detection.ts +147 -147
  221. package/node_modules/@sdd-agent-platform/core/src/config/starter-documents.ts +400 -445
  222. package/node_modules/@sdd-agent-platform/core/src/context/budget.ts +30 -30
  223. package/node_modules/@sdd-agent-platform/core/src/context/build-package.ts +305 -317
  224. package/node_modules/@sdd-agent-platform/core/src/context/command-summary.ts +45 -45
  225. package/node_modules/@sdd-agent-platform/core/src/context/context-build.test.ts +188 -188
  226. package/node_modules/@sdd-agent-platform/core/src/context/evidence-summary.ts +144 -144
  227. package/node_modules/@sdd-agent-platform/core/src/context/log-worker.ts +48 -48
  228. package/node_modules/@sdd-agent-platform/core/src/context/source-refs.ts +41 -41
  229. package/node_modules/@sdd-agent-platform/core/src/context-offload/contracts.ts +47 -47
  230. package/node_modules/@sdd-agent-platform/core/src/context-offload/runtime.test.ts +71 -71
  231. package/node_modules/@sdd-agent-platform/core/src/context-offload/runtime.ts +178 -178
  232. package/node_modules/@sdd-agent-platform/core/src/context-offload.ts +2 -2
  233. package/node_modules/@sdd-agent-platform/core/src/context.ts +6 -6
  234. package/node_modules/@sdd-agent-platform/core/src/contracts/issues.ts +13 -13
  235. package/node_modules/@sdd-agent-platform/core/src/contracts.test.ts +9 -9
  236. package/node_modules/@sdd-agent-platform/core/src/contracts.ts +121 -115
  237. package/node_modules/@sdd-agent-platform/core/src/delegation/delegation.test.ts +183 -183
  238. package/node_modules/@sdd-agent-platform/core/src/delegation/model.ts +23 -23
  239. package/node_modules/@sdd-agent-platform/core/src/delegation/queue.ts +58 -58
  240. package/node_modules/@sdd-agent-platform/core/src/delegation/run-state.ts +14 -14
  241. package/node_modules/@sdd-agent-platform/core/src/delegation/state-machine.ts +90 -90
  242. package/node_modules/@sdd-agent-platform/core/src/delegation/validation.ts +124 -124
  243. package/node_modules/@sdd-agent-platform/core/src/delegation.ts +26 -26
  244. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/ai-entries.ts +28 -28
  245. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/document-chain.ts +104 -112
  246. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/local-run-index.ts +27 -27
  247. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/project.ts +84 -84
  248. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/registries.ts +252 -252
  249. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/run-evidence.ts +330 -330
  250. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/run-records.ts +79 -79
  251. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/run-trust.ts +128 -128
  252. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/runtime-contracts.ts +300 -300
  253. package/node_modules/@sdd-agent-platform/core/src/doctor/doctor.test.ts +627 -657
  254. package/node_modules/@sdd-agent-platform/core/src/doctor/doctor.ts +301 -318
  255. package/node_modules/@sdd-agent-platform/core/src/doctor/model.ts +13 -13
  256. package/node_modules/@sdd-agent-platform/core/src/doctor/summary.ts +11 -11
  257. package/node_modules/@sdd-agent-platform/core/src/doctor.ts +2 -2
  258. package/node_modules/@sdd-agent-platform/core/src/evidence/lookup.ts +80 -80
  259. package/node_modules/@sdd-agent-platform/core/src/evidence-runtime/contracts.ts +48 -49
  260. package/node_modules/@sdd-agent-platform/core/src/evidence-runtime.ts +1 -1
  261. package/node_modules/@sdd-agent-platform/core/src/execution/agent-execution-records.ts +195 -195
  262. package/node_modules/@sdd-agent-platform/core/src/execution/background-executor.test.ts +187 -187
  263. package/node_modules/@sdd-agent-platform/core/src/execution/background-executor.ts +305 -305
  264. package/node_modules/@sdd-agent-platform/core/src/execution/foreground-subagents.test.ts +97 -97
  265. package/node_modules/@sdd-agent-platform/core/src/execution/foreground-subagents.ts +453 -453
  266. package/node_modules/@sdd-agent-platform/core/src/execution/host-invocation.ts +225 -225
  267. package/node_modules/@sdd-agent-platform/core/src/execution/resident-worker.test.ts +132 -132
  268. package/node_modules/@sdd-agent-platform/core/src/execution/resident-worker.ts +436 -436
  269. package/node_modules/@sdd-agent-platform/core/src/execution/stage-team-runtime.test.ts +102 -102
  270. package/node_modules/@sdd-agent-platform/core/src/execution/stage-team-runtime.ts +271 -271
  271. package/node_modules/@sdd-agent-platform/core/src/execution/wave-executor.test.ts +111 -111
  272. package/node_modules/@sdd-agent-platform/core/src/execution/wave-executor.ts +231 -231
  273. package/node_modules/@sdd-agent-platform/core/src/execution.ts +5 -5
  274. package/node_modules/@sdd-agent-platform/core/src/governance/policy.test.ts +57 -57
  275. package/node_modules/@sdd-agent-platform/core/src/governance/policy.ts +175 -175
  276. package/node_modules/@sdd-agent-platform/core/src/governance.ts +1 -1
  277. package/node_modules/@sdd-agent-platform/core/src/instructions.test.ts +80 -49
  278. package/node_modules/@sdd-agent-platform/core/src/instructions.ts +38 -81
  279. package/node_modules/@sdd-agent-platform/core/src/lifecycle/decision-gate.test.ts +174 -174
  280. package/node_modules/@sdd-agent-platform/core/src/lifecycle/decision-gate.ts +373 -373
  281. package/node_modules/@sdd-agent-platform/core/src/lifecycle/rendering.ts +29 -29
  282. package/node_modules/@sdd-agent-platform/core/src/lifecycle/risk-signals.ts +146 -146
  283. package/node_modules/@sdd-agent-platform/core/src/lifecycle/ship.test.ts +47 -0
  284. package/node_modules/@sdd-agent-platform/core/src/lifecycle/ship.ts +255 -263
  285. package/node_modules/@sdd-agent-platform/core/src/lifecycle-graph/contracts.ts +179 -0
  286. package/node_modules/@sdd-agent-platform/core/src/lifecycle-graph/kernel.ts +522 -0
  287. package/node_modules/@sdd-agent-platform/core/src/lifecycle-graph.ts +2 -0
  288. package/node_modules/@sdd-agent-platform/core/src/lifecycle.ts +4 -4
  289. package/node_modules/@sdd-agent-platform/core/src/orchestration/contracts.ts +50 -50
  290. package/node_modules/@sdd-agent-platform/core/src/orchestration/index.ts +2 -2
  291. package/node_modules/@sdd-agent-platform/core/src/orchestration/runtime.ts +331 -342
  292. package/node_modules/@sdd-agent-platform/core/src/path-safety.test.ts +22 -22
  293. package/node_modules/@sdd-agent-platform/core/src/phase8-contracts.test.ts +243 -243
  294. package/node_modules/@sdd-agent-platform/core/src/phase8-projection-compat.test.ts +152 -153
  295. package/node_modules/@sdd-agent-platform/core/src/phase8-risk-kernel.test.ts +277 -277
  296. package/node_modules/@sdd-agent-platform/core/src/phase9-lifecycle-graph.test.ts +103 -0
  297. package/node_modules/@sdd-agent-platform/core/src/planning/task-graph.test.ts +88 -88
  298. package/node_modules/@sdd-agent-platform/core/src/planning/task-graph.ts +222 -222
  299. package/node_modules/@sdd-agent-platform/core/src/planning/wave-plan.test.ts +79 -79
  300. package/node_modules/@sdd-agent-platform/core/src/planning/wave-plan.ts +160 -160
  301. package/node_modules/@sdd-agent-platform/core/src/planning.ts +2 -2
  302. package/node_modules/@sdd-agent-platform/core/src/registries/agent-capability-catalog.ts +426 -426
  303. package/node_modules/@sdd-agent-platform/core/src/registries/agent-registry.ts +230 -146
  304. package/node_modules/@sdd-agent-platform/core/src/registries/agent-runtime-static.ts +142 -142
  305. package/node_modules/@sdd-agent-platform/core/src/registries/capability-sources.ts +253 -253
  306. package/node_modules/@sdd-agent-platform/core/src/registries/command-team-runtime.ts +302 -309
  307. package/node_modules/@sdd-agent-platform/core/src/registries/eval-learning-context.ts +246 -246
  308. package/node_modules/@sdd-agent-platform/core/src/registries/plan-scout-domains.ts +89 -0
  309. package/node_modules/@sdd-agent-platform/core/src/registries/query-status.ts +119 -119
  310. package/node_modules/@sdd-agent-platform/core/src/registries/registries.test.ts +454 -429
  311. package/node_modules/@sdd-agent-platform/core/src/registries/skill-capabilities.ts +37 -37
  312. package/node_modules/@sdd-agent-platform/core/src/registries/tool-capabilities.ts +135 -135
  313. package/node_modules/@sdd-agent-platform/core/src/registries/tool-plugins.ts +132 -132
  314. package/node_modules/@sdd-agent-platform/core/src/registries/worker-adapters.ts +144 -144
  315. package/node_modules/@sdd-agent-platform/core/src/registries/workflow-gates.ts +111 -111
  316. package/node_modules/@sdd-agent-platform/core/src/registries.ts +42 -42
  317. package/node_modules/@sdd-agent-platform/core/src/risk/consumer-diagnostics.ts +98 -97
  318. package/node_modules/@sdd-agent-platform/core/src/risk/contracts.ts +63 -63
  319. package/node_modules/@sdd-agent-platform/core/src/risk/kernel.ts +233 -233
  320. package/node_modules/@sdd-agent-platform/core/src/risk/legacy-adapters.ts +251 -266
  321. package/node_modules/@sdd-agent-platform/core/src/risk/workflow-gates.ts +203 -203
  322. package/node_modules/@sdd-agent-platform/core/src/risk.ts +5 -5
  323. package/node_modules/@sdd-agent-platform/core/src/router/agent-runtime-config.ts +327 -327
  324. package/node_modules/@sdd-agent-platform/core/src/router/agent-runtime.ts +388 -388
  325. package/node_modules/@sdd-agent-platform/core/src/router/profile-resolution.ts +154 -154
  326. package/node_modules/@sdd-agent-platform/core/src/router/risk-policy.ts +33 -33
  327. package/node_modules/@sdd-agent-platform/core/src/router/route-cache.ts +100 -100
  328. package/node_modules/@sdd-agent-platform/core/src/router/route-projection.ts +356 -356
  329. package/node_modules/@sdd-agent-platform/core/src/router/route-sdd-task.test.ts +428 -428
  330. package/node_modules/@sdd-agent-platform/core/src/router/route-sdd-task.ts +2 -2
  331. package/node_modules/@sdd-agent-platform/core/src/router/routing-rules.ts +73 -73
  332. package/node_modules/@sdd-agent-platform/core/src/router/routing.ts +189 -191
  333. package/node_modules/@sdd-agent-platform/core/src/router/runtime-import.ts +464 -0
  334. package/node_modules/@sdd-agent-platform/core/src/router/runtime-inspection.ts +124 -124
  335. package/node_modules/@sdd-agent-platform/core/src/router/runtime-registry.ts +123 -123
  336. package/node_modules/@sdd-agent-platform/core/src/router/runtime-validation.ts +277 -277
  337. package/node_modules/@sdd-agent-platform/core/src/router/stage-route-binding.ts +273 -0
  338. package/node_modules/@sdd-agent-platform/core/src/router/team-mode.ts +170 -170
  339. package/node_modules/@sdd-agent-platform/core/src/router.ts +5 -4
  340. package/node_modules/@sdd-agent-platform/core/src/run-state/artifacts.ts +126 -118
  341. package/node_modules/@sdd-agent-platform/core/src/run-state/events.ts +27 -27
  342. package/node_modules/@sdd-agent-platform/core/src/run-state/inspect-run.ts +172 -172
  343. package/node_modules/@sdd-agent-platform/core/src/run-state/invocation-ledger.ts +109 -109
  344. package/node_modules/@sdd-agent-platform/core/src/run-state/model.ts +252 -230
  345. package/node_modules/@sdd-agent-platform/core/src/run-state/run-index.test.ts +52 -52
  346. package/node_modules/@sdd-agent-platform/core/src/run-state/run-index.ts +356 -356
  347. package/node_modules/@sdd-agent-platform/core/src/run-state/run-state.test.ts +70 -70
  348. package/node_modules/@sdd-agent-platform/core/src/run-state/run-state.ts +406 -406
  349. package/node_modules/@sdd-agent-platform/core/src/run-state/task-evidence.ts +198 -206
  350. package/node_modules/@sdd-agent-platform/core/src/run-state/timing.ts +146 -0
  351. package/node_modules/@sdd-agent-platform/core/src/run-state.ts +8 -8
  352. package/node_modules/@sdd-agent-platform/core/src/runtime-analysis/build.ts +60 -63
  353. package/node_modules/@sdd-agent-platform/core/src/runtime-analysis/findings.ts +257 -296
  354. package/node_modules/@sdd-agent-platform/core/src/runtime-analysis/model.ts +140 -152
  355. package/node_modules/@sdd-agent-platform/core/src/runtime-analysis.test.ts +66 -68
  356. package/node_modules/@sdd-agent-platform/core/src/runtime-analysis.ts +2 -2
  357. package/node_modules/@sdd-agent-platform/core/src/runtime-paths.ts +253 -176
  358. package/node_modules/@sdd-agent-platform/core/src/runtime-projection-p0.test.ts +101 -0
  359. package/node_modules/@sdd-agent-platform/core/src/runtime-projection-p0.ts +314 -0
  360. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/artifact-depth.test.ts +380 -0
  361. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/artifact-depth.ts +207 -0
  362. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/context.ts +111 -111
  363. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/document-hashes.ts +207 -207
  364. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/run-binding.ts +95 -95
  365. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/task-inspection.ts +39 -39
  366. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/task-parser.test.ts +467 -401
  367. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/task-parser.ts +738 -694
  368. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/task-rendering.ts +81 -81
  369. package/node_modules/@sdd-agent-platform/core/src/sdd-docs.ts +5 -5
  370. package/node_modules/@sdd-agent-platform/core/src/spec-manager-contracts.ts +13 -0
  371. package/node_modules/@sdd-agent-platform/core/src/stage-artifacts.ts +435 -0
  372. package/node_modules/@sdd-agent-platform/core/src/stage-collaboration-contracts.ts +316 -0
  373. package/node_modules/@sdd-agent-platform/core/src/stage-collaboration.test.ts +2964 -0
  374. package/node_modules/@sdd-agent-platform/core/src/stage-collaboration.ts +5856 -0
  375. package/node_modules/@sdd-agent-platform/core/src/stage-runtime/contracts.ts +40 -40
  376. package/node_modules/@sdd-agent-platform/core/src/stage-runtime/runtime.test.ts +209 -209
  377. package/node_modules/@sdd-agent-platform/core/src/stage-runtime/runtime.ts +360 -352
  378. package/node_modules/@sdd-agent-platform/core/src/stage-runtime.ts +2 -2
  379. package/node_modules/@sdd-agent-platform/core/src/status/project-status.test.ts +288 -288
  380. package/node_modules/@sdd-agent-platform/core/src/status/project-status.ts +651 -625
  381. package/node_modules/@sdd-agent-platform/core/src/status.ts +2 -2
  382. package/node_modules/@sdd-agent-platform/core/src/storage/json-io.ts +10 -10
  383. package/node_modules/@sdd-agent-platform/core/src/storage/runtime-store.test.ts +489 -489
  384. package/node_modules/@sdd-agent-platform/core/src/storage/runtime-store.ts +1981 -1175
  385. package/node_modules/@sdd-agent-platform/core/src/subagents/contracts.ts +45 -45
  386. package/node_modules/@sdd-agent-platform/core/src/subagents/runtime.test.ts +232 -232
  387. package/node_modules/@sdd-agent-platform/core/src/subagents/runtime.ts +307 -307
  388. package/node_modules/@sdd-agent-platform/core/src/subagents.ts +2 -2
  389. package/node_modules/@sdd-agent-platform/core/src/task-execution-contract.test.ts +141 -0
  390. package/node_modules/@sdd-agent-platform/core/src/task-execution-contract.ts +566 -0
  391. package/node_modules/@sdd-agent-platform/core/src/task-risk-profile.ts +193 -193
  392. package/node_modules/@sdd-agent-platform/core/src/test-support/fixtures.ts +413 -398
  393. package/node_modules/@sdd-agent-platform/core/src/test-support/run-state.ts +102 -70
  394. package/node_modules/@sdd-agent-platform/core/src/test-support.ts +2 -2
  395. package/node_modules/@sdd-agent-platform/core/src/truth-reconciliation.test.ts +72 -0
  396. package/node_modules/@sdd-agent-platform/core/src/truth-reconciliation.ts +174 -0
  397. package/node_modules/@sdd-agent-platform/core/src/verification/rendering.ts +137 -181
  398. package/node_modules/@sdd-agent-platform/core/src/verification/review-gate.test.ts +77 -77
  399. package/node_modules/@sdd-agent-platform/core/src/verification/review-gate.ts +77 -77
  400. package/node_modules/@sdd-agent-platform/core/src/verification/single-task-loop.ts +455 -494
  401. package/node_modules/@sdd-agent-platform/core/src/verification/{goal-verify.test.ts → task-evidence-judgment.test.ts} +261 -335
  402. package/node_modules/@sdd-agent-platform/core/src/verification/{goal-verify.ts → task-evidence-judgment.ts} +619 -648
  403. package/node_modules/@sdd-agent-platform/core/src/verification/test-runtime.ts +1190 -1032
  404. package/node_modules/@sdd-agent-platform/core/src/verification/validation-cache.ts +106 -0
  405. package/node_modules/@sdd-agent-platform/core/src/verification/validation-wave.ts +513 -513
  406. package/node_modules/@sdd-agent-platform/core/src/verification/verify-contract.ts +334 -358
  407. package/node_modules/@sdd-agent-platform/core/src/verification.ts +8 -8
  408. package/node_modules/@sdd-agent-platform/core/src/work-units/contracts.ts +26 -26
  409. package/node_modules/@sdd-agent-platform/core/src/work-units/runtime.test.ts +88 -88
  410. package/node_modules/@sdd-agent-platform/core/src/work-units/runtime.ts +112 -112
  411. package/node_modules/@sdd-agent-platform/core/src/work-units.ts +2 -2
  412. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/evidence-packet.ts +190 -196
  413. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/hard-checks.test.ts +169 -171
  414. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/hard-checks.ts +136 -143
  415. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/policy.test.ts +135 -137
  416. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/policy.ts +153 -155
  417. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/types.ts +111 -114
  418. package/node_modules/@sdd-agent-platform/core/src/workflow-state/affected-file-conflicts.ts +95 -95
  419. package/node_modules/@sdd-agent-platform/core/src/workflow-state/dependencies.test.ts +32 -32
  420. package/node_modules/@sdd-agent-platform/core/src/workflow-state/dependencies.ts +114 -114
  421. package/node_modules/@sdd-agent-platform/core/src/workflow-state/latest-eligible-run.ts +184 -156
  422. package/node_modules/@sdd-agent-platform/core/src/workflow-state/migration-recovery.ts +158 -0
  423. package/node_modules/@sdd-agent-platform/core/src/workflow-state/repair-contract.ts +77 -0
  424. package/node_modules/@sdd-agent-platform/core/src/workflow-state/resolve-task-run.ts +114 -0
  425. package/node_modules/@sdd-agent-platform/core/src/workflow-state/resolve.test.ts +970 -464
  426. package/node_modules/@sdd-agent-platform/core/src/workflow-state/resolve.ts +967 -363
  427. package/node_modules/@sdd-agent-platform/core/src/workflow-state/runtime-projections.ts +712 -0
  428. package/node_modules/@sdd-agent-platform/core/src/workflow-state.ts +2 -2
  429. package/node_modules/@sdd-agent-platform/core/src/worktree/isolation.ts +130 -130
  430. package/node_modules/@sdd-agent-platform/core/src/worktree/lifecycle.ts +269 -269
  431. package/node_modules/@sdd-agent-platform/core/src/worktree/worktree.test.ts +150 -150
  432. package/node_modules/@sdd-agent-platform/core/src/worktree.ts +2 -2
  433. package/node_modules/@sdd-agent-platform/core/tsconfig.json +15 -15
  434. package/package.json +2 -2
  435. package/packages/cli/dist/args.js +1 -1
  436. package/packages/cli/dist/args.js.map +1 -1
  437. package/packages/cli/dist/commands/context.js +1 -1
  438. package/packages/cli/dist/commands/context.js.map +1 -1
  439. package/packages/cli/dist/commands/evidence.js.map +1 -0
  440. package/packages/cli/dist/commands/execution.js +126 -0
  441. package/packages/cli/dist/commands/execution.js.map +1 -1
  442. package/packages/cli/dist/commands/instructions.d.ts +1 -1
  443. package/packages/cli/dist/commands/instructions.js +15 -1
  444. package/packages/cli/dist/commands/instructions.js.map +1 -1
  445. package/packages/cli/dist/commands/registry/runtime.js +70 -1
  446. package/packages/cli/dist/commands/registry/runtime.js.map +1 -1
  447. package/packages/cli/dist/commands/run.js +12 -1
  448. package/packages/cli/dist/commands/run.js.map +1 -1
  449. package/packages/cli/dist/commands/stage-close.d.ts +66 -0
  450. package/packages/cli/dist/commands/stage-close.js +524 -0
  451. package/packages/cli/dist/commands/stage-close.js.map +1 -0
  452. package/packages/cli/dist/commands/status.js +8 -1
  453. package/packages/cli/dist/commands/status.js.map +1 -1
  454. package/packages/cli/dist/commands/tasks.js.map +1 -1
  455. package/packages/cli/dist/dispatch.js +6 -31
  456. package/packages/cli/dist/dispatch.js.map +1 -1
  457. package/packages/cli/dist/help.js +153 -158
  458. package/packages/cli/dist/help.js.map +1 -1
  459. package/packages/cli/dist/renderers/workflow.d.ts +51 -2
  460. package/packages/cli/dist/renderers/workflow.js.map +1 -1
  461. package/packages/cli/dist/skill-import-args.d.ts +10 -0
  462. package/packages/cli/dist/skill-import-args.js +47 -0
  463. package/packages/cli/dist/skill-import-args.js.map +1 -0
  464. package/packages/cli/dist/tsconfig.tsbuildinfo +1 -1
  465. package/packages/cli/package.json +2 -2
  466. package/packages/core/dist/ai-tools.js +84 -103
  467. package/packages/core/dist/ai-tools.js.map +1 -1
  468. package/packages/core/dist/config/init-project.d.ts +10 -6
  469. package/packages/core/dist/config/init-project.js +7 -8
  470. package/packages/core/dist/config/init-project.js.map +1 -1
  471. package/packages/core/dist/config/project-config.d.ts +3 -1
  472. package/packages/core/dist/config/project-config.js +7 -3
  473. package/packages/core/dist/config/project-config.js.map +1 -1
  474. package/packages/core/dist/config/starter-documents.d.ts +0 -1
  475. package/packages/core/dist/config/starter-documents.js +374 -421
  476. package/packages/core/dist/config/starter-documents.js.map +1 -1
  477. package/packages/core/dist/context/build-package.d.ts +1 -1
  478. package/packages/core/dist/context/build-package.js +7 -19
  479. package/packages/core/dist/context/build-package.js.map +1 -1
  480. package/packages/core/dist/contracts.d.ts +7 -1
  481. package/packages/core/dist/contracts.js +6 -0
  482. package/packages/core/dist/contracts.js.map +1 -1
  483. package/packages/core/dist/doctor/checks/document-chain.js +2 -12
  484. package/packages/core/dist/doctor/checks/document-chain.js.map +1 -1
  485. package/packages/core/dist/doctor/doctor.js +1 -18
  486. package/packages/core/dist/doctor/doctor.js.map +1 -1
  487. package/packages/core/dist/evidence/lookup.d.ts +1 -1
  488. package/packages/core/dist/evidence/lookup.js +1 -1
  489. package/packages/core/dist/evidence/lookup.js.map +1 -1
  490. package/packages/core/dist/evidence-runtime/contracts.d.ts +0 -1
  491. package/packages/core/dist/evidence-runtime/coordination.js +110 -0
  492. package/packages/core/dist/evidence-runtime/coordination.js.map +1 -0
  493. package/packages/core/dist/execution/host-invocation.js +83 -83
  494. package/packages/core/dist/instructions.d.ts +1 -1
  495. package/packages/core/dist/instructions.js +37 -80
  496. package/packages/core/dist/instructions.js.map +1 -1
  497. package/packages/core/dist/lifecycle/ship.js +58 -68
  498. package/packages/core/dist/lifecycle/ship.js.map +1 -1
  499. package/packages/core/dist/lifecycle-graph/contracts.d.ts +159 -0
  500. package/packages/core/dist/lifecycle-graph/contracts.js +7 -0
  501. package/packages/core/dist/lifecycle-graph/contracts.js.map +1 -0
  502. package/packages/core/dist/lifecycle-graph/kernel.d.ts +16 -0
  503. package/packages/core/dist/lifecycle-graph/kernel.js +461 -0
  504. package/packages/core/dist/lifecycle-graph/kernel.js.map +1 -0
  505. package/packages/core/dist/lifecycle-graph.d.ts +2 -0
  506. package/packages/core/dist/lifecycle-graph.js +3 -0
  507. package/packages/core/dist/lifecycle-graph.js.map +1 -0
  508. package/packages/core/dist/orchestration/contracts.d.ts +1 -1
  509. package/packages/core/dist/orchestration/runtime.js +21 -28
  510. package/packages/core/dist/orchestration/runtime.js.map +1 -1
  511. package/packages/core/dist/registries/agent-registry.js +124 -40
  512. package/packages/core/dist/registries/agent-registry.js.map +1 -1
  513. package/packages/core/dist/registries/command-team-runtime.d.ts +1 -1
  514. package/packages/core/dist/registries/command-team-runtime.js +6 -13
  515. package/packages/core/dist/registries/command-team-runtime.js.map +1 -1
  516. package/packages/core/dist/registries/plan-scout-domains.d.ts +13 -0
  517. package/packages/core/dist/registries/plan-scout-domains.js +76 -0
  518. package/packages/core/dist/registries/plan-scout-domains.js.map +1 -0
  519. package/packages/core/dist/registries/skill-capabilities.js +7 -7
  520. package/packages/core/dist/registries/skill-capabilities.js.map +1 -1
  521. package/packages/core/dist/registries/tool-capabilities.js +6 -6
  522. package/packages/core/dist/registries/tool-capabilities.js.map +1 -1
  523. package/packages/core/dist/registries/workflow-gates.d.ts +1 -1
  524. package/packages/core/dist/registries/workflow-gates.js +18 -18
  525. package/packages/core/dist/registries/workflow-gates.js.map +1 -1
  526. package/packages/core/dist/risk/consumer-diagnostics.js +2 -1
  527. package/packages/core/dist/risk/consumer-diagnostics.js.map +1 -1
  528. package/packages/core/dist/risk/contracts.d.ts +2 -2
  529. package/packages/core/dist/risk/kernel.js +7 -7
  530. package/packages/core/dist/risk/kernel.js.map +1 -1
  531. package/packages/core/dist/risk/legacy-adapters.js +12 -27
  532. package/packages/core/dist/risk/legacy-adapters.js.map +1 -1
  533. package/packages/core/dist/risk/workflow-gates.js +6 -6
  534. package/packages/core/dist/risk/workflow-gates.js.map +1 -1
  535. package/packages/core/dist/router/agent-runtime-config.js +1 -1
  536. package/packages/core/dist/router/agent-runtime-config.js.map +1 -1
  537. package/packages/core/dist/router/routing.js +2 -4
  538. package/packages/core/dist/router/routing.js.map +1 -1
  539. package/packages/core/dist/router/runtime-import.d.ts +28 -0
  540. package/packages/core/dist/router/runtime-import.js +383 -0
  541. package/packages/core/dist/router/runtime-import.js.map +1 -0
  542. package/packages/core/dist/router/stage-route-binding.d.ts +37 -0
  543. package/packages/core/dist/router/stage-route-binding.js +227 -0
  544. package/packages/core/dist/router/stage-route-binding.js.map +1 -0
  545. package/packages/core/dist/router.d.ts +1 -0
  546. package/packages/core/dist/router.js +1 -0
  547. package/packages/core/dist/router.js.map +1 -1
  548. package/packages/core/dist/run-state/artifacts.d.ts +16 -0
  549. package/packages/core/dist/run-state/artifacts.js +6 -0
  550. package/packages/core/dist/run-state/artifacts.js.map +1 -1
  551. package/packages/core/dist/run-state/model.d.ts +20 -0
  552. package/packages/core/dist/run-state/run-state.js +7 -7
  553. package/packages/core/dist/run-state/run-state.js.map +1 -1
  554. package/packages/core/dist/run-state/task-evidence.d.ts +1 -2
  555. package/packages/core/dist/run-state/task-evidence.js +2 -9
  556. package/packages/core/dist/run-state/task-evidence.js.map +1 -1
  557. package/packages/core/dist/run-state/timing.d.ts +8 -0
  558. package/packages/core/dist/run-state/timing.js +131 -0
  559. package/packages/core/dist/run-state/timing.js.map +1 -0
  560. package/packages/core/dist/runtime-analysis/build.js +1 -4
  561. package/packages/core/dist/runtime-analysis/build.js.map +1 -1
  562. package/packages/core/dist/runtime-analysis/findings.js +0 -39
  563. package/packages/core/dist/runtime-analysis/findings.js.map +1 -1
  564. package/packages/core/dist/runtime-analysis/model.d.ts +1 -17
  565. package/packages/core/dist/runtime-paths.d.ts +10 -0
  566. package/packages/core/dist/runtime-paths.js +65 -0
  567. package/packages/core/dist/runtime-paths.js.map +1 -1
  568. package/packages/core/dist/runtime-projection-p0.d.ts +64 -0
  569. package/packages/core/dist/runtime-projection-p0.js +211 -0
  570. package/packages/core/dist/runtime-projection-p0.js.map +1 -0
  571. package/packages/core/dist/sdd-docs/artifact-depth.d.ts +14 -0
  572. package/packages/core/dist/sdd-docs/artifact-depth.js +179 -0
  573. package/packages/core/dist/sdd-docs/artifact-depth.js.map +1 -0
  574. package/packages/core/dist/sdd-docs/task-parser.d.ts +5 -1
  575. package/packages/core/dist/sdd-docs/task-parser.js +60 -22
  576. package/packages/core/dist/sdd-docs/task-parser.js.map +1 -1
  577. package/packages/core/dist/sdd-docs/task-rendering.js +2 -2
  578. package/packages/core/dist/sdd-docs/task-rendering.js.map +1 -1
  579. package/packages/core/dist/spec-entry.js +40 -0
  580. package/packages/core/dist/spec-entry.js.map +1 -0
  581. package/packages/core/dist/spec-manager-contracts.d.ts +12 -0
  582. package/packages/core/dist/spec-manager-contracts.js +2 -0
  583. package/packages/core/dist/spec-manager-contracts.js.map +1 -0
  584. package/packages/core/dist/stage-artifacts.d.ts +55 -0
  585. package/packages/core/dist/stage-artifacts.js +315 -0
  586. package/packages/core/dist/stage-artifacts.js.map +1 -0
  587. package/packages/core/dist/stage-collaboration-contracts.d.ts +55 -0
  588. package/packages/core/dist/stage-collaboration-contracts.js +238 -0
  589. package/packages/core/dist/stage-collaboration-contracts.js.map +1 -0
  590. package/packages/core/dist/stage-collaboration.d.ts +736 -0
  591. package/packages/core/dist/stage-collaboration.js +4018 -0
  592. package/packages/core/dist/stage-collaboration.js.map +1 -0
  593. package/packages/core/dist/stage-runtime/runtime.js +8 -1
  594. package/packages/core/dist/stage-runtime/runtime.js.map +1 -1
  595. package/packages/core/dist/status/project-status.js +25 -1
  596. package/packages/core/dist/status/project-status.js.map +1 -1
  597. package/packages/core/dist/storage/runtime-store.d.ts +170 -18
  598. package/packages/core/dist/storage/runtime-store.js +597 -85
  599. package/packages/core/dist/storage/runtime-store.js.map +1 -1
  600. package/packages/core/dist/sync-back/apply.d.ts +1 -17
  601. package/packages/core/dist/sync-back/apply.js +1 -242
  602. package/packages/core/dist/sync-back/apply.js.map +1 -1
  603. package/packages/core/dist/sync-back/inspect.d.ts +1 -110
  604. package/packages/core/dist/sync-back/inspect.js +1 -496
  605. package/packages/core/dist/sync-back/inspect.js.map +1 -1
  606. package/packages/core/dist/sync-back.d.ts +1 -2
  607. package/packages/core/dist/sync-back.js +1 -2
  608. package/packages/core/dist/sync-back.js.map +1 -1
  609. package/packages/core/dist/task-execution-contract.d.ts +167 -0
  610. package/packages/core/dist/task-execution-contract.js +377 -0
  611. package/packages/core/dist/task-execution-contract.js.map +1 -0
  612. package/packages/core/dist/test-support/fixtures.js +329 -314
  613. package/packages/core/dist/test-support/fixtures.js.map +1 -1
  614. package/packages/core/dist/test-support/run-state.d.ts +1 -0
  615. package/packages/core/dist/test-support/run-state.js +31 -0
  616. package/packages/core/dist/test-support/run-state.js.map +1 -1
  617. package/packages/core/dist/truth-reconciliation.d.ts +44 -0
  618. package/packages/core/dist/truth-reconciliation.js +135 -0
  619. package/packages/core/dist/truth-reconciliation.js.map +1 -0
  620. package/packages/core/dist/tsconfig.tsbuildinfo +1 -1
  621. package/packages/core/dist/verification/goal-verify.d.ts +0 -49
  622. package/packages/core/dist/verification/goal-verify.js +1 -545
  623. package/packages/core/dist/verification/goal-verify.js.map +1 -1
  624. package/packages/core/dist/verification/rendering.d.ts +5 -7
  625. package/packages/core/dist/verification/rendering.js +15 -55
  626. package/packages/core/dist/verification/rendering.js.map +1 -1
  627. package/packages/core/dist/verification/single-task-loop.js +1 -40
  628. package/packages/core/dist/verification/single-task-loop.js.map +1 -1
  629. package/packages/core/dist/verification/task-evidence-judgment.d.ts +49 -0
  630. package/packages/core/dist/verification/task-evidence-judgment.js +521 -0
  631. package/packages/core/dist/verification/task-evidence-judgment.js.map +1 -0
  632. package/packages/core/dist/verification/test-runtime.d.ts +12 -2
  633. package/packages/core/dist/verification/test-runtime.js +247 -112
  634. package/packages/core/dist/verification/test-runtime.js.map +1 -1
  635. package/packages/core/dist/verification/validation-cache.d.ts +26 -0
  636. package/packages/core/dist/verification/validation-cache.js +73 -0
  637. package/packages/core/dist/verification/validation-cache.js.map +1 -0
  638. package/packages/core/dist/verification/verify-contract.d.ts +1 -1
  639. package/packages/core/dist/verification/verify-contract.js +49 -72
  640. package/packages/core/dist/verification/verify-contract.js.map +1 -1
  641. package/packages/core/dist/verification.d.ts +3 -3
  642. package/packages/core/dist/verification.js +2 -2
  643. package/packages/core/dist/verification.js.map +1 -1
  644. package/packages/core/dist/workflow-gate/evidence-packet.js +2 -7
  645. package/packages/core/dist/workflow-gate/evidence-packet.js.map +1 -1
  646. package/packages/core/dist/workflow-gate/hard-checks.js +0 -7
  647. package/packages/core/dist/workflow-gate/hard-checks.js.map +1 -1
  648. package/packages/core/dist/workflow-gate/policy.js +2 -4
  649. package/packages/core/dist/workflow-gate/policy.js.map +1 -1
  650. package/packages/core/dist/workflow-gate/types.d.ts +3 -5
  651. package/packages/core/dist/workflow-state/latest-eligible-run.js +30 -4
  652. package/packages/core/dist/workflow-state/latest-eligible-run.js.map +1 -1
  653. package/packages/core/dist/workflow-state/migration-recovery.d.ts +40 -0
  654. package/packages/core/dist/workflow-state/migration-recovery.js +110 -0
  655. package/packages/core/dist/workflow-state/migration-recovery.js.map +1 -0
  656. package/packages/core/dist/workflow-state/repair-contract.d.ts +12 -0
  657. package/packages/core/dist/workflow-state/repair-contract.js +63 -0
  658. package/packages/core/dist/workflow-state/repair-contract.js.map +1 -0
  659. package/packages/core/dist/workflow-state/resolve-task-run.d.ts +21 -0
  660. package/packages/core/dist/workflow-state/resolve-task-run.js +95 -0
  661. package/packages/core/dist/workflow-state/resolve-task-run.js.map +1 -0
  662. package/packages/core/dist/workflow-state/resolve.d.ts +55 -5
  663. package/packages/core/dist/workflow-state/resolve.js +518 -36
  664. package/packages/core/dist/workflow-state/resolve.js.map +1 -1
  665. package/packages/core/dist/workflow-state/runtime-projections.d.ts +228 -0
  666. package/packages/core/dist/workflow-state/runtime-projections.js +452 -0
  667. package/packages/core/dist/workflow-state/runtime-projections.js.map +1 -0
  668. package/packages/core/package.json +6 -3
  669. package/tsconfig.build.json +6 -7
  670. package/node_modules/@sdd-agent-platform/core/dist/doctor/render.d.ts +0 -2
  671. package/node_modules/@sdd-agent-platform/core/dist/doctor/render.js +0 -44
  672. package/node_modules/@sdd-agent-platform/core/dist/doctor/render.js.map +0 -1
  673. package/node_modules/@sdd-agent-platform/core/src/sync-back/apply.ts +0 -270
  674. package/node_modules/@sdd-agent-platform/core/src/sync-back/inspect.ts +0 -655
  675. package/node_modules/@sdd-agent-platform/core/src/sync-back/sync-back.test.ts +0 -569
  676. package/node_modules/@sdd-agent-platform/core/src/sync-back.ts +0 -2
  677. package/node_modules/@sdd-agent-platform/core/src/verification/single-task-loop.test.ts +0 -255
  678. package/node_modules/@sdd-agent-platform/core/src/verification/test-runtime.test.ts +0 -439
  679. package/node_modules/@sdd-agent-platform/core/src/verification/validation-wave.test.ts +0 -341
  680. package/node_modules/@sdd-agent-platform/core/src/verification/verify-contract.test.ts +0 -204
  681. package/packages/cli/dist/commands/lifecycle.d.ts +0 -6
  682. package/packages/cli/dist/commands/lifecycle.js +0 -112
  683. package/packages/cli/dist/commands/lifecycle.js.map +0 -1
  684. package/packages/cli/dist/commands/sync-back.d.ts +0 -6
  685. package/packages/cli/dist/commands/sync-back.js +0 -82
  686. package/packages/cli/dist/commands/sync-back.js.map +0 -1
  687. package/packages/cli/dist/commands/test.d.ts +0 -6
  688. package/packages/cli/dist/commands/test.js +0 -195
  689. package/packages/cli/dist/commands/test.js.map +0 -1
  690. package/packages/cli/dist/commands/verifies.d.ts +0 -6
  691. package/packages/cli/dist/commands/verifies.js +0 -85
  692. package/packages/cli/dist/commands/verifies.js.map +0 -1
  693. package/packages/cli/dist/commands/verify.d.ts +0 -6
  694. package/packages/cli/dist/commands/verify.js +0 -134
  695. package/packages/cli/dist/commands/verify.js.map +0 -1
  696. package/packages/core/dist/doctor/render.d.ts +0 -2
  697. package/packages/core/dist/doctor/render.js +0 -44
  698. package/packages/core/dist/doctor/render.js.map +0 -1
@@ -1,657 +1,627 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import { execFile } from 'node:child_process';
4
- import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
5
- import { tmpdir } from 'node:os';
6
- import path from 'node:path';
7
- import { promisify } from 'node:util';
8
-
9
- import { ingestArtifactResult } from '../artifacts/ingestion.js';
10
- import { initProject } from '../config/init-project.js';
11
- import { createDelegationRecord } from '../delegation/validation.js';
12
- import { writeArtifact } from '../run-state/artifacts.js';
13
- import { appendEvent, readRunEvents } from '../run-state/events.js';
14
- import { rebuildLocalRunIndex } from '../run-state/run-index.js';
15
- import { archiveRun, createRun, readRunState, writeRunState } from '../run-state/run-state.js';
16
- import { validResultArtifact, validTaskMarkdown, writeBranchDocs } from '../test-support/fixtures.js';
17
- import { bindTestRunState } from '../test-support/run-state.js';
18
- import { STAGE_RUN_CONTRACT_VERSION, SUBAGENT_DISPATCH_CONTRACT_VERSION, WORKFLOW_HANDOFF_CONTRACT_VERSION, type RuntimeScope } from '../contracts.js';
19
- import { recordStageRunProjection, recordWorkflowHandoffProjection, type StageRun, type WorkflowHandoff } from '../stage-runtime.js';
20
- import { decideContextOffload, evaluateContextLoadSignal, recordContextLoadSignalProjection, recordContextOffloadDecisionProjection } from '../context-offload.js';
21
- import { recordSubagentDispatchProjection, type SubagentDispatch } from '../subagents.js';
22
- import { runShip } from '../lifecycle/ship.js';
23
- import { recordRuntimeSyncBackDecision, runtimeScopedId, withRuntimeStore } from '../storage/runtime-store.js';
24
- import { getProjectStatus } from '../status/project-status.js';
25
- import { doctor } from './doctor.js';
26
-
27
- const execFileAsync = promisify(execFile);
28
-
29
-
30
- test('doctor reports AI entry drift after init', async () => {
31
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-doctor-drift-'));
32
- try {
33
- await initProject(root);
34
- const skillPath = path.join(root, '.claude', 'skills', 'sdd', 'SKILL.md');
35
- await writeFile(skillPath, `${await readFile(skillPath, 'utf8')}\nmanual drift\n`, 'utf8');
36
-
37
- const report = await doctor(root);
38
-
39
- assert.equal(report.status, 'FAIL');
40
- assert.equal(report.checks.some((check) => check.check === 'ai_entry_sdd' && check.level === 'FAIL' && /will not overwrite user-modified/.test(check.action ?? '')), true);
41
- } finally {
42
- await rm(root, { recursive: true, force: true });
43
- }
44
- });
45
-
46
- test('doctor reports missing git repo as fail in temp directory', async () => {
47
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-runtime-'));
48
- try {
49
- await initProject(root);
50
- const report = await doctor(root);
51
- assert.equal(report.status, 'FAIL');
52
- assert.equal(report.checks.some((check) => check.check === 'git_repo' && check.level === 'FAIL'), true);
53
- assert.equal(report.checks.some((check) => check.check === 'git_repo' && /git init/.test(check.action ?? '')), true);
54
- } finally {
55
- await rm(root, { recursive: true, force: true });
56
- }
57
- });
58
-
59
- test('doctor reports broken document-chain refs and high-risk evidence gaps', async () => {
60
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-document-chain-doctor-'));
61
- try {
62
- await initProject(root);
63
- await writeBranchDocs(root, 'master', `# Tasks
64
-
65
- ### D1: Broken document chain
66
-
67
- \`\`\`sdd-task
68
- id: D1
69
- status: pending
70
- wave: 1
71
- depends_on: []
72
- acceptance_refs:
73
- - AC-404
74
- affected_files:
75
- - packages/core/src/index.ts
76
- validation:
77
- - npm test
78
- risk:
79
- - database
80
- \`\`\`
81
-
82
- #### Boundary
83
-
84
- Stay inside document-chain checks.
85
-
86
- #### Acceptance
87
-
88
- - Broken ref is detected.
89
- `);
90
- await writeFile(path.join(root, 'specs', 'master', 'spec.md'), '# Spec\n\n| ID | Acceptance |\n|---|---|\n| AC-1 | Existing acceptance. |\n', 'utf8');
91
-
92
- const report = await doctor(root, { latestOnly: true });
93
-
94
- assert.equal(report.checks.some((check) => check.check === 'document_chain_acceptance_ref' && check.level === 'FAIL' && /AC-404/.test(check.message)), true);
95
- assert.equal(report.checks.some((check) => check.check === 'document_chain_high_risk_evidence' && check.level === 'FAIL' && /D1/.test(check.message)), true);
96
- } finally {
97
- await rm(root, { recursive: true, force: true });
98
- }
99
- });
100
-
101
- test('doctor reports local run index drift with rebuild action', async () => {
102
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-local-index-doctor-'));
103
- try {
104
- await initProject(root);
105
- const run = await createRun(root, { runId: 'run-1' });
106
- await rebuildLocalRunIndex(root);
107
- await writeRunState(root, { ...run, status: 'completed', tasks: { T2: { status: 'completed' } } });
108
-
109
- const report = await doctor(root);
110
-
111
- assert.equal(report.checks.some((check) => check.check === 'local_run_index' && check.level === 'WARN' && /rebuild/.test(check.action ?? '')), true);
112
- assert.equal(report.checks.some((check) => check.check === 'local_run_index_contract' && check.level === 'PASS'), true);
113
- } finally {
114
- await rm(root, { recursive: true, force: true });
115
- }
116
- });
117
-
118
- test('doctor reports artifact writes attached to unscoped runs', async () => {
119
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-doctor-artifact-scope-'));
120
- try {
121
- await initProject(root);
122
- const state = await createRun(root, { runId: 'run-1' });
123
- await writeArtifact(root, state.runId, 'review-T1.md', validResultArtifact('reviewer', 'T1', 'PASS', 'artifacts/review-T1.md'));
124
-
125
- const report = await doctor(root, { allRuns: true });
126
-
127
- assert.equal(report.checks.some((check) => check.check === 'artifact_scope' && check.level === 'FAIL' && /unscoped run/.test(check.message)), true);
128
- } finally {
129
- await rm(root, { recursive: true, force: true });
130
- }
131
- });
132
-
133
- test('doctor reports stale delegation and terminal event gaps without auto-fix', async () => {
134
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-doctor-hardening-'));
135
- try {
136
- await initProject(root);
137
- const state = await createRun(root, { runId: 'run-1' });
138
- const stale = createDelegationRecord({
139
- delegationId: 'D-T1-reviewer-001',
140
- task: 'T1',
141
- agent: 'reviewer',
142
- expectedArtifact: 'artifacts/review-T1.md',
143
- startedAt: '2020-01-01T00:00:00.000Z',
144
- timeoutSeconds: 1
145
- });
146
- const completed = createDelegationRecord({
147
- delegationId: 'D-T1-validator-001',
148
- task: 'T1',
149
- agent: 'validator',
150
- expectedArtifact: 'artifacts/validation-T1.md',
151
- status: 'COMPLETED'
152
- });
153
- await writeRunState(root, { ...state, delegations: { [stale.delegationId]: stale, [completed.delegationId]: completed } });
154
- await appendEvent(root, state.runId, { event: 'delegation_started', runId: state.runId, data: { delegationId: stale.delegationId } });
155
-
156
- const report = await doctor(root);
157
-
158
- assert.equal(report.status, 'FAIL');
159
- assert.equal(report.checks.some((check) => check.check === 'stale_delegation'), true);
160
- assert.equal(report.checks.some((check) => check.check === 'terminal_event_missing'), true);
161
- assert.equal(report.checks.some((check) => check.check === 'artifact_invalid'), true);
162
- } finally {
163
- await rm(root, { recursive: true, force: true });
164
- }
165
- });
166
-
167
- test('archiveRun cancels running delegations and normal doctor skips archived evidence', async () => {
168
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-archive-run-'));
169
- try {
170
- await initProject(root);
171
- const state = await createRun(root, { runId: 'run-1' });
172
- const running = createDelegationRecord({
173
- delegationId: 'D-T1-reviewer-001',
174
- task: 'T1',
175
- agent: 'reviewer',
176
- expectedArtifact: 'artifacts/review-T1.md',
177
- startedAt: '2020-01-01T00:00:00.000Z',
178
- timeoutSeconds: 1
179
- });
180
- await writeRunState(root, { ...state, delegations: { [running.delegationId]: running } });
181
- await appendEvent(root, state.runId, { event: 'delegation_started', runId: state.runId, data: { delegationId: running.delegationId } });
182
-
183
- const archived = await archiveRun(root, state.runId, { reason: 'exploratory failure' });
184
- const normalDoctor = await doctor(root);
185
- const allRunsDoctor = await doctor(root, { allRuns: true });
186
- const events = await readRunEvents(root, state.runId);
187
-
188
- assert.equal(archived.status, 'archived');
189
- assert.equal(archived.delegations[running.delegationId].status, 'CANCELLED');
190
- assert.equal(events.some((event) => event.event === 'delegation_cancelled'), true);
191
- assert.equal(events.some((event) => event.event === 'run_archived'), true);
192
- assert.equal(normalDoctor.checks.some((check) => check.check === 'stale_delegation'), false);
193
- assert.equal(normalDoctor.checks.some((check) => check.check === 'run_evidence_scope'), true);
194
- assert.equal(allRunsDoctor.checks.some((check) => check.check === 'stale_delegation'), false);
195
- } finally {
196
- await rm(root, { recursive: true, force: true });
197
- }
198
- });
199
-
200
- test('doctor latestOnly ignores older failed run evidence', async () => {
201
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-doctor-latest-only-'));
202
- try {
203
- await initProject(root);
204
- const older = await createRun(root, { runId: 'run-older' });
205
- const newer = await createRun(root, { runId: 'run-newer' });
206
- const stale = createDelegationRecord({
207
- delegationId: 'D-T1-reviewer-001',
208
- task: 'T1',
209
- agent: 'reviewer',
210
- expectedArtifact: 'artifacts/review-T1.md',
211
- startedAt: '2020-01-01T00:00:00.000Z',
212
- timeoutSeconds: 1
213
- });
214
- await writeRunState(root, { ...older, updatedAt: '2026-05-01T00:00:00.000Z', delegations: { [stale.delegationId]: stale } });
215
- await writeRunState(root, { ...newer, updatedAt: '2026-05-02T00:00:00.000Z' });
216
- await appendEvent(root, older.runId, { event: 'delegation_started', runId: older.runId, data: { delegationId: stale.delegationId } });
217
-
218
- const latestOnly = await doctor(root, { latestOnly: true });
219
- const allRuns = await doctor(root, { allRuns: true });
220
-
221
- assert.equal(latestOnly.checks.some((check) => check.check === 'stale_delegation'), false);
222
- assert.equal(latestOnly.checks.some((check) => check.check === 'run_evidence_fast_path'), true);
223
- assert.equal(allRuns.checks.some((check) => check.check === 'stale_delegation'), true);
224
- } finally {
225
- await rm(root, { recursive: true, force: true });
226
- }
227
- });
228
-
229
- test('doctor trust suite flags mention-only acceptance and weak validator PASS artifacts', async () => {
230
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-doctor-trust-'));
231
- try {
232
- await initProject(root);
233
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
234
- const state = await createRun(root, { runId: 'run-1' });
235
- await bindTestRunState(root, state.runId, 'feature', 'T1');
236
- await writeArtifact(root, state.runId, 'validation-T1.md', validResultArtifact('validator', 'T1', 'PASS', 'artifacts/validation-T1.md'));
237
- const restored = await readRunState(root, state.runId);
238
- await writeRunState(root, {
239
- ...restored,
240
- status: 'completed',
241
- validation: {
242
- status: 'pass',
243
- commands: ['npm test'],
244
- evidence: ['artifacts/validation-T1.md']
245
- },
246
- tasks: {
247
- T1: {
248
- status: 'verified',
249
- verifyStatus: 'PASS',
250
- gaps: [],
251
- artifacts: ['artifacts/validation-T1.md'],
252
- acceptanceCoverage: [{ acceptance: 'AC-1', status: 'PASS', evidence: 'Mentioned in artifacts/validation-T1.md.' }]
253
- }
254
- },
255
- artifacts: [{ path: 'artifacts/validation-T1.md', kind: 'validation', task: 'T1', agent: 'validator', createdAt: new Date().toISOString() }]
256
- });
257
-
258
- const report = await doctor(root, { allRuns: true, branch: 'feature' });
259
-
260
- assert.equal(report.checks.some((check) => check.check === 'acceptance_trust' && check.level === 'FAIL'), true);
261
- assert.equal(report.checks.some((check) => check.check === 'artifact_trust' && check.level === 'FAIL' && /UNSOURCED_PASS/.test(check.message)), true);
262
- } finally {
263
- await rm(root, { recursive: true, force: true });
264
- }
265
- });
266
-
267
- test('doctor reports artifact ingestion state mismatch', async () => {
268
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-artifact-ingest-doctor-'));
269
- try {
270
- await initProject(root);
271
- const state = await createRun(root, { runId: 'run-1' });
272
- const delegation = createDelegationRecord({
273
- delegationId: 'D-T1-reviewer-001',
274
- task: 'T1',
275
- agent: 'reviewer',
276
- expectedArtifact: 'artifacts/review-T1.md'
277
- });
278
- await writeRunState(root, { ...state, delegations: { [delegation.delegationId]: delegation } });
279
- await appendEvent(root, state.runId, { event: 'delegation_started', runId: state.runId, data: { delegationId: delegation.delegationId } });
280
- await writeArtifact(root, state.runId, 'review-T1.md', `# Review
281
-
282
- \`\`\`sdd-result
283
- contract: sdd-result-v1
284
- version: 1.3.0
285
- agent: reviewer
286
- task: T1
287
- status: PASS
288
- artifacts:
289
- - artifacts/review-T1.md
290
- \`\`\`
291
- `);
292
- const ingested = await ingestArtifactResult(root, state.runId, { delegationId: delegation.delegationId, artifactPath: 'artifacts/review-T1.md' });
293
- const acceptedState = await readRunState(root, state.runId);
294
- await writeRunState(root, {
295
- ...acceptedState,
296
- artifacts: [],
297
- artifactIngestions: {
298
- [`${delegation.delegationId}:artifacts/review-T1.md`]: ingested.record
299
- }
300
- });
301
-
302
- const report = await doctor(root);
303
-
304
- assert.equal(report.status, 'FAIL');
305
- assert.equal(report.checks.some((check) => check.check === 'artifact_result_ingestion' && /missing from run artifact index/.test(check.message)), true);
306
- } finally {
307
- await rm(root, { recursive: true, force: true });
308
- }
309
- });
310
-
311
- test('doctor honors explicit branch for document-chain scope', async () => {
312
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-doctor-branch-'));
313
- try {
314
- await initProject(root);
315
- await execFileAsync('git', ['init'], { cwd: root });
316
- await execFileAsync('git', ['checkout', '-b', 'other'], { cwd: root });
317
-
318
- const report = await doctor(root, { latestOnly: true, branch: 'master' });
319
-
320
- assert.equal(report.checks.some((check) => /Document chain skipped for other/.test(check.message)), false);
321
- assert.equal(report.checks.some((check) => check.check.startsWith('document_chain')), true);
322
- } finally {
323
- await rm(root, { recursive: true, force: true });
324
- }
325
- });
326
-
327
- test('doctor reports workflow handoff state diagnostics', async () => {
328
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-doctor-handoff-'));
329
- try {
330
- await initProject(root);
331
- await recordStageRunProjection(root, doctorStageRun());
332
- await recordWorkflowHandoffProjection(root, doctorHandoff());
333
-
334
- const report = await doctor(root, { latestOnly: true, branch: 'master' });
335
-
336
- assert.equal(report.checks.some((check) => check.check === 'workflow_handoff_state' && check.level === 'PASS' && /status=fresh/.test(check.message)), true);
337
- assert.equal(report.checks.some((check) => check.check === 'workflow_handoff_state' && /do->test:accepted/.test(check.message)), true);
338
- } finally {
339
- await rm(root, { recursive: true, force: true });
340
- }
341
- });
342
-
343
- test('doctor reports context offload and subagent dispatch state diagnostics', async () => {
344
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-doctor-context-subagent-'));
345
- try {
346
- await initProject(root);
347
- const signal = evaluateContextLoadSignal({
348
- scope: doctorScope,
349
- refs: [{ kind: 'document', ref: 'specs/master/tasks.md' }],
350
- fileCount: 20,
351
- artifactBytes: 200_000,
352
- dependencyFanout: 12,
353
- unknownImpact: true,
354
- generatedAt: '2026-05-18T00:00:00.000Z'
355
- });
356
- await recordContextLoadSignalProjection(root, signal);
357
- await recordContextOffloadDecisionProjection(root, decideContextOffload(signal, { dispatchRefs: [{ kind: 'projection', ref: 'phase8_subagent_dispatch:master:T1:run-1:none:dispatch-1' }] }));
358
- await recordSubagentDispatchProjection(root, doctorSubagentDispatch());
359
-
360
- const report = await doctor(root, { latestOnly: true, branch: 'master' });
361
-
362
- assert.equal(report.checks.some((check) => check.check === 'context_offload_state' && check.level === 'PASS' && /level=high action=dispatch-subagent/.test(check.message)), true);
363
- assert.equal(report.checks.some((check) => check.check === 'subagent_dispatch_state' && check.level === 'FAIL' && /status=blocked/.test(check.message)), true);
364
- } finally {
365
- await rm(root, { recursive: true, force: true });
366
- }
367
- });
368
-
369
- test('archived failed subagent dispatch no longer blocks doctor or ship subagent gates', async () => {
370
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-doctor-archived-subagent-'));
371
- try {
372
- await initProject(root);
373
- await createRun(root, { runId: 'run-1' });
374
- await recordSubagentDispatchProjection(root, {
375
- ...doctorSubagentDispatch(),
376
- status: 'failed',
377
- updatedAt: '2026-05-18T00:02:00.000Z'
378
- });
379
- const failed = await doctor(root, { latestOnly: true, branch: 'master' });
380
- assert.equal(failed.checks.some((check) => check.check === 'subagent_dispatch_state' && check.level === 'FAIL' && /status=failed/.test(check.message)), true);
381
-
382
- await archiveRun(root, 'run-1', { reason: 'failed subagent superseded by rerun' });
383
- const recovered = await doctor(root, { latestOnly: true, branch: 'master' });
384
- const ship = await runShip(root, { branch: 'master', dryRun: true });
385
-
386
- assert.equal(recovered.checks.some((check) => check.check === 'subagent_dispatch_state' && check.level === 'PASS' && /status=missing/.test(check.message)), true);
387
- assert.equal(ship.checks.some((check) => check.name === 'subagent_dispatches' && check.status === 'PASS' && /status=missing/.test(check.message)), true);
388
- } finally {
389
- await rm(root, { recursive: true, force: true });
390
- }
391
- });
392
-
393
- test('doctor reports unavailable Phase 8 runtime checks as warnings', async () => {
394
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-doctor-runtime-unavailable-'));
395
- try {
396
- await initProject(root);
397
- await withRuntimeStore(root, ({ db }) => {
398
- db.prepare('INSERT INTO projections (projection_id, projection_type, scope_key, generated_at, payload_json) VALUES (?, ?, ?, ?, ?)')
399
- .run('bad-context-build', 'context_build', 'master:T1:run-1:none', new Date().toISOString(), '{');
400
- });
401
-
402
- const report = await doctor(root, { latestOnly: true, branch: 'master' });
403
-
404
- assert.equal(report.checks.some((check) => check.check === 'lifecycle_risk_decision' && check.level === 'WARN' && /unavailable/.test(check.message)), true);
405
- assert.equal(report.checks.some((check) => check.check === 'workflow_handoff_state' && check.level === 'WARN' && /unavailable/.test(check.message)), true);
406
- assert.equal(report.checks.some((check) => check.check === 'context_offload_state' && check.level === 'WARN' && /unavailable/.test(check.message)), true);
407
- assert.equal(report.checks.some((check) => check.check === 'subagent_dispatch_state' && check.level === 'WARN' && /unavailable/.test(check.message)), true);
408
- } finally {
409
- await rm(root, { recursive: true, force: true });
410
- }
411
- });
412
-
413
- test('Phase 8.9 surfaces capability health in status, doctor, and ship gates', async () => {
414
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-capability-health-'));
415
- try {
416
- await initProject(root);
417
- await writeBranchDocs(root, 'master', capabilityHealthTaskMarkdown('SECURITY'));
418
-
419
- const status = await getProjectStatus(root, { branch: 'master' });
420
- const report = await doctor(root, { latestOnly: true, branch: 'master' });
421
- const ship = await runShip(root, { branch: 'master', dryRun: true });
422
- const doctorCheck = report.checks.find((check) => check.check === 'capability_health');
423
- const shipCheck = ship.checks.find((check) => check.name === 'capability_health');
424
-
425
- assert.equal(status.capabilityHealth.status, 'warn');
426
- assert.equal(status.capabilityHealth.missingBaselineDomains.length, 0);
427
- assert.equal(status.capabilityHealth.sources.quarantined > 0, true);
428
- assert.equal(status.capabilityHealth.sources.denied > 0, true);
429
- assert.deepEqual(status.capabilityHealth.releaseCriticalGaps, ['security-engineering']);
430
- assert.equal(status.capabilityHealth.warnings.some((warning) => /release-critical capability gap security-engineering/.test(warning)), true);
431
- assert.equal(doctorCheck?.level, 'WARN');
432
- assert.match(doctorCheck?.message ?? '', /release_critical_gaps=security-engineering/);
433
- assert.equal(shipCheck?.status, 'PASS');
434
- assert.match(shipCheck?.message ?? '', /release_critical_gaps=security-engineering/);
435
- assert.equal(shipCheck?.nextAction, undefined);
436
- } finally {
437
- await rm(root, { recursive: true, force: true });
438
- }
439
- });
440
-
441
- test('ship reports token pressure as diagnostic pass', async () => {
442
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-ship-token-diagnostic-'));
443
- try {
444
- await initProject(root);
445
- await withRuntimeStore(root, ({ db }) => {
446
- db.prepare('INSERT INTO projections (projection_id, projection_type, scope_key, generated_at, payload_json) VALUES (?, ?, ?, ?, ?)')
447
- .run('context-build-pressure', 'context_build', 'master:T1:run-1:none', '2026-05-18T00:00:00.000Z', JSON.stringify({
448
- taskId: 'T1',
449
- profile: 'normal',
450
- budget: { estimatedBytes: 900, maxBytes: 1000, estimatedTokens: 225 }
451
- }));
452
- });
453
-
454
- const ship = await runShip(root, { branch: 'master', dryRun: true });
455
- const tokenCheck = ship.checks.find((check) => check.name === 'token_health');
456
-
457
- assert.equal(tokenCheck?.status, 'PASS');
458
- assert.match(tokenCheck?.message ?? '', /token_health=pressure/);
459
- } finally {
460
- await rm(root, { recursive: true, force: true });
461
- }
462
- });
463
-
464
- test('ship accepts validated runs without requiring sync-back apply', async () => {
465
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-ship-syncback-not-required-'));
466
- try {
467
- await initProject(root);
468
- await writeBranchDocs(root, 'master', validTaskMarkdown('T1', []));
469
- const state = await createRun(root, { runId: 'run-1' });
470
- await bindTestRunState(root, state.runId, 'master', 'T1');
471
- const bound = await readRunState(root, state.runId);
472
- await writeRunState(root, {
473
- ...bound,
474
- status: 'completed',
475
- validation: {
476
- status: 'pass',
477
- commands: ['npm test'],
478
- evidence: []
479
- }
480
- });
481
-
482
- const ship = await runShip(root, { branch: 'master', dryRun: true });
483
- const latestRunCheck = ship.checks.find((check) => check.name === 'latest_run');
484
-
485
- assert.equal(latestRunCheck?.status, 'PASS');
486
- assert.match(latestRunCheck?.message ?? '', /sync_back=not_created/);
487
- } finally {
488
- await rm(root, { recursive: true, force: true });
489
- }
490
- });
491
-
492
- test('doctor reports Phase 8.18 compatibility and Phase 9 readiness diagnostics', async () => {
493
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-phase818-doctor-'));
494
- try {
495
- await initProject(root);
496
- await writeBranchDocs(root, 'master', validTaskMarkdown('T1', []));
497
- const state = await createRun(root, { runId: 'run-1', branch: 'master', taskId: 'T1' });
498
- await writeArtifact(root, state.runId, 'review-T1.md', validResultArtifact('reviewer', 'T1', 'PASS', 'artifacts/review-T1.md'));
499
- const legacyRunDir = path.join(root, '.sdd', 'runs', state.runId);
500
- await mkdir(path.join(legacyRunDir, 'agent-executions'), { recursive: true });
501
- await writeFile(path.join(legacyRunDir, 'state.json'), '{}', 'utf8');
502
- await writeFile(path.join(legacyRunDir, 'events.jsonl'), '{}\n', 'utf8');
503
- await writeFile(path.join(legacyRunDir, 'invocations.jsonl'), '{}\n', 'utf8');
504
- await writeFile(path.join(legacyRunDir, 'agent-executions', 'legacy.json'), '{}', 'utf8');
505
- await writeRunState(root, {
506
- ...state,
507
- syncBack: {
508
- ...state.syncBack,
509
- status: 'proposed',
510
- proposalPath: 'artifacts/sync-back-proposal.md',
511
- proposalDigest: 'legacy-digest'
512
- }
513
- });
514
- await recordRuntimeSyncBackDecision(root, {
515
- decisionId: runtimeScopedId(state.runId, 'T1', 'sync-back'),
516
- runId: state.runId,
517
- branch: 'master',
518
- taskId: 'T1',
519
- status: 'blocked',
520
- proposalPath: 'artifacts/sync-back-proposal.md',
521
- proposalDigest: 'legacy-digest',
522
- proposalPayloadId: null,
523
- reasons: ['legacy divergence'],
524
- createdAt: '2026-05-21T00:00:00.000Z',
525
- updatedAt: '2026-05-21T00:00:00.000Z',
526
- payload: {}
527
- });
528
-
529
- const report = await doctor(root, { allRuns: true, branch: 'master' });
530
-
531
- const legacyRunFiles = report.checks.find((check) => check.check === 'phase8_18_legacy_run_files');
532
- assert.equal(legacyRunFiles?.level, 'WARN');
533
- assert.match(legacyRunFiles?.message ?? '', /run-1:state\.json/);
534
- assert.match(legacyRunFiles?.message ?? '', /run-1:events\.jsonl/);
535
- assert.match(legacyRunFiles?.message ?? '', /run-1:invocations\.jsonl/);
536
- assert.doesNotMatch(legacyRunFiles?.message ?? '', /evidence/);
537
- assert.equal(report.checks.some((check) => check.check === 'phase8_18_legacy_sidecars' && check.level === 'WARN' && /run-1/.test(check.message)), true);
538
- assert.equal(report.checks.some((check) => check.check === 'phase8_18_sync_back_compat' && check.level === 'WARN' && /proposed->blocked/.test(check.message)), true);
539
- assert.equal(report.checks.some((check) => check.check === 'phase9_readiness' && check.level === 'PASS' && /optional_advisory_only/.test(check.message)), true);
540
- } finally {
541
- await rm(root, { recursive: true, force: true });
542
- }
543
- });
544
-
545
- test('ship still blocks context offload curation', async () => {
546
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-ship-context-curation-'));
547
- try {
548
- await initProject(root);
549
- const signal = evaluateContextLoadSignal({
550
- scope: doctorScope,
551
- fileCount: 50,
552
- artifactBytes: 600_000,
553
- dependencyFanout: 30,
554
- unknownImpact: true,
555
- generatedAt: '2026-05-18T00:00:00.000Z'
556
- });
557
- await recordContextLoadSignalProjection(root, signal);
558
- await recordContextOffloadDecisionProjection(root, decideContextOffload(signal));
559
-
560
- const ship = await runShip(root, { branch: 'master', dryRun: true });
561
- const contextCheck = ship.checks.find((check) => check.name === 'context_offload');
562
-
563
- assert.equal(contextCheck?.status, 'BLOCKED');
564
- assert.match(contextCheck?.message ?? '', /action=block-for-curation/);
565
- assert.equal(ship.nextActions.some((action) => /Curate context before ship/.test(action)), true);
566
- } finally {
567
- await rm(root, { recursive: true, force: true });
568
- }
569
- });
570
-
571
- function capabilityHealthTaskMarkdown(taskId: string): string {
572
- return `# Tasks
573
-
574
- ### ${taskId}: Security readiness task
575
-
576
- \`\`\`sdd-task
577
- id: ${taskId}
578
- status: pending
579
- wave: 1
580
- depends_on: []
581
- acceptance_refs:
582
- - AC-1
583
- affected_files:
584
- - packages/core/src/auth.ts
585
- validation:
586
- - npm test
587
- risk:
588
- - security
589
- \`\`\`
590
-
591
- #### Boundary
592
-
593
- Stay inside security readiness fixtures.
594
-
595
- #### Acceptance
596
-
597
- - AC-1: Security readiness is covered.
598
- `;
599
- }
600
-
601
- const doctorScope: RuntimeScope = { branch: 'master', taskId: 'T1', runId: 'run-1' };
602
-
603
- function doctorStageRun(): StageRun {
604
- return {
605
- contract: STAGE_RUN_CONTRACT_VERSION,
606
- id: 'doctor-stage-do',
607
- scope: doctorScope,
608
- stage: 'do',
609
- ownerAgent: 'implementer',
610
- coMainAgents: ['reviewer'],
611
- status: 'completed',
612
- inputRefs: [{ kind: 'projection', ref: 'phase8_lifecycle_risk_decision:master:T1:run-1:none' }],
613
- outputRefs: [{ kind: 'artifact', ref: 'artifacts/doctor-handoff.md' }],
614
- decisionRefs: [{ kind: 'projection', ref: 'phase8_lifecycle_risk_decision:master:T1:run-1:none' }],
615
- blockingReasons: [],
616
- createdAt: '2026-05-18T00:00:00.000Z',
617
- updatedAt: '2026-05-18T00:01:00.000Z'
618
- };
619
- }
620
-
621
- function doctorHandoff(): WorkflowHandoff {
622
- return {
623
- contract: WORKFLOW_HANDOFF_CONTRACT_VERSION,
624
- id: 'doctor-handoff-do-test',
625
- scope: doctorScope,
626
- fromStage: 'do',
627
- toStage: 'test',
628
- fromAgent: 'implementer',
629
- toAgent: 'validator',
630
- status: 'accepted',
631
- outputRefs: [{ kind: 'artifact', ref: 'artifacts/doctor-handoff.md' }],
632
- requiredInputRefs: [{ kind: 'projection', ref: 'phase8_lifecycle_risk_decision:master:T1:run-1:none' }],
633
- riskDecisionRef: { kind: 'projection', ref: 'phase8_lifecycle_risk_decision:master:T1:run-1:none' },
634
- evidenceRefs: [{ kind: 'evidence', ref: 'artifacts/doctor-handoff-validation.md#AC-1' }],
635
- openQuestions: [],
636
- blockingGaps: [],
637
- createdAt: '2026-05-18T00:02:00.000Z',
638
- decidedAt: '2026-05-18T00:03:00.000Z'
639
- };
640
- }
641
-
642
- function doctorSubagentDispatch(): SubagentDispatch {
643
- return {
644
- contract: SUBAGENT_DISPATCH_CONTRACT_VERSION,
645
- id: 'dispatch-1',
646
- scope: doctorScope,
647
- workUnitId: 'wu-subagent-1',
648
- definitionName: 'test-writer',
649
- mode: 'background',
650
- status: 'queued',
651
- blocking: true,
652
- requiredBefore: 'handoff',
653
- contextRef: { kind: 'projection', ref: 'sdd-scoped-context-handoff:T1' },
654
- createdAt: '2026-05-18T00:00:00.000Z',
655
- updatedAt: '2026-05-18T00:01:00.000Z'
656
- };
657
- }
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { execFile } from 'node:child_process';
4
+ import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
5
+ import { tmpdir } from 'node:os';
6
+ import path from 'node:path';
7
+ import { promisify } from 'node:util';
8
+
9
+ import { ingestArtifactResult } from '../artifacts/ingestion.js';
10
+ import { initProject } from '../config/init-project.js';
11
+ import { createDelegationRecord } from '../delegation/validation.js';
12
+ import { writeArtifact } from '../run-state/artifacts.js';
13
+ import { appendEvent, readRunEvents } from '../run-state/events.js';
14
+ import { rebuildLocalRunIndex } from '../run-state/run-index.js';
15
+ import { archiveRun, createRun, readRunState, writeRunState } from '../run-state/run-state.js';
16
+ import { validResultArtifact, validTaskMarkdown, writeBranchDocs } from '../test-support/fixtures.js';
17
+ import { bindTestRunState } from '../test-support/run-state.js';
18
+ import { STAGE_RUN_CONTRACT_VERSION, SUBAGENT_DISPATCH_CONTRACT_VERSION, WORKFLOW_HANDOFF_CONTRACT_VERSION, type RuntimeScope } from '../contracts.js';
19
+ import { recordStageRunProjection, recordWorkflowHandoffProjection, type StageRun, type WorkflowHandoff } from '../stage-runtime.js';
20
+ import { decideContextOffload, evaluateContextLoadSignal, recordContextLoadSignalProjection, recordContextOffloadDecisionProjection } from '../context-offload.js';
21
+ import { recordSubagentDispatchProjection, type SubagentDispatch } from '../subagents.js';
22
+ import { runShip } from '../lifecycle/ship.js';
23
+ import { withRuntimeStore } from '../storage/runtime-store.js';
24
+ import { getProjectStatus } from '../status/project-status.js';
25
+ import { doctor } from './doctor.js';
26
+
27
+ const execFileAsync = promisify(execFile);
28
+
29
+
30
+ test('doctor reports AI entry drift after init', async () => {
31
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-doctor-drift-'));
32
+ try {
33
+ await initProject(root);
34
+ const skillPath = path.join(root, '.claude', 'skills', 'sdd', 'SKILL.md');
35
+ await writeFile(skillPath, `${await readFile(skillPath, 'utf8')}\nmanual drift\n`, 'utf8');
36
+
37
+ const report = await doctor(root);
38
+
39
+ assert.equal(report.status, 'FAIL');
40
+ assert.equal(report.checks.some((check) => check.check === 'ai_entry_sdd' && check.level === 'FAIL' && /will not overwrite user-modified/.test(check.action ?? '')), true);
41
+ } finally {
42
+ await rm(root, { recursive: true, force: true });
43
+ }
44
+ });
45
+
46
+ test('doctor reports missing git repo as fail in temp directory', async () => {
47
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-runtime-'));
48
+ try {
49
+ await initProject(root);
50
+ const report = await doctor(root);
51
+ assert.equal(report.status, 'FAIL');
52
+ assert.equal(report.checks.some((check) => check.check === 'git_repo' && check.level === 'FAIL'), true);
53
+ assert.equal(report.checks.some((check) => check.check === 'git_repo' && /git init/.test(check.action ?? '')), true);
54
+ } finally {
55
+ await rm(root, { recursive: true, force: true });
56
+ }
57
+ });
58
+
59
+ test('doctor reports broken document-chain refs and high-risk evidence gaps', async () => {
60
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-document-chain-doctor-'));
61
+ try {
62
+ await initProject(root);
63
+ await writeBranchDocs(root, 'master', `# Tasks
64
+
65
+ ### D1: Broken document chain
66
+
67
+ \`\`\`sdd-task
68
+ id: D1
69
+ status: pending
70
+ wave: 1
71
+ depends_on: []
72
+ acceptance_refs:
73
+ - AC-404
74
+ affected_files:
75
+ - packages/core/src/index.ts
76
+ validation:
77
+ - npm test
78
+ risk:
79
+ - database
80
+ \`\`\`
81
+
82
+ #### Boundary
83
+
84
+ Stay inside document-chain checks.
85
+
86
+ #### Acceptance
87
+
88
+ - Broken ref is detected.
89
+ `);
90
+ await writeFile(path.join(root, 'specs', 'master', 'spec.md'), '# Spec\n\n| ID | Acceptance |\n|---|---|\n| AC-1 | Existing acceptance. |\n', 'utf8');
91
+
92
+ const report = await doctor(root, { latestOnly: true });
93
+
94
+ assert.equal(report.checks.some((check) => check.check === 'document_chain_acceptance_ref' && check.level === 'FAIL' && /AC-404/.test(check.message)), true);
95
+ assert.equal(report.checks.some((check) => check.check === 'document_chain_high_risk_evidence' && check.level === 'FAIL' && /D1/.test(check.message)), true);
96
+ } finally {
97
+ await rm(root, { recursive: true, force: true });
98
+ }
99
+ });
100
+
101
+ test('doctor reports local run index drift with rebuild action', async () => {
102
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-local-index-doctor-'));
103
+ try {
104
+ await initProject(root);
105
+ const run = await createRun(root, { runId: 'run-1' });
106
+ await rebuildLocalRunIndex(root);
107
+ await writeRunState(root, { ...run, status: 'completed', tasks: { T2: { status: 'completed' } } });
108
+
109
+ const report = await doctor(root);
110
+
111
+ assert.equal(report.checks.some((check) => check.check === 'local_run_index' && check.level === 'WARN' && /rebuild/.test(check.action ?? '')), true);
112
+ assert.equal(report.checks.some((check) => check.check === 'local_run_index_contract' && check.level === 'PASS'), true);
113
+ } finally {
114
+ await rm(root, { recursive: true, force: true });
115
+ }
116
+ });
117
+
118
+ test('doctor reports artifact writes attached to unscoped runs', async () => {
119
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-doctor-artifact-scope-'));
120
+ try {
121
+ await initProject(root);
122
+ const state = await createRun(root, { runId: 'run-1' });
123
+ await writeArtifact(root, state.runId, 'review-T1.md', validResultArtifact('reviewer', 'T1', 'PASS', 'artifacts/review-T1.md'));
124
+
125
+ const report = await doctor(root, { allRuns: true });
126
+
127
+ assert.equal(report.checks.some((check) => check.check === 'artifact_scope' && check.level === 'FAIL' && /unscoped run/.test(check.message)), true);
128
+ } finally {
129
+ await rm(root, { recursive: true, force: true });
130
+ }
131
+ });
132
+
133
+ test('doctor reports stale delegation and terminal event gaps without auto-fix', async () => {
134
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-doctor-hardening-'));
135
+ try {
136
+ await initProject(root);
137
+ const state = await createRun(root, { runId: 'run-1' });
138
+ const stale = createDelegationRecord({
139
+ delegationId: 'D-T1-reviewer-001',
140
+ task: 'T1',
141
+ agent: 'reviewer',
142
+ expectedArtifact: 'artifacts/review-T1.md',
143
+ startedAt: '2020-01-01T00:00:00.000Z',
144
+ timeoutSeconds: 1
145
+ });
146
+ const completed = createDelegationRecord({
147
+ delegationId: 'D-T1-validator-001',
148
+ task: 'T1',
149
+ agent: 'validator',
150
+ expectedArtifact: 'artifacts/validation-T1.md',
151
+ status: 'COMPLETED'
152
+ });
153
+ await writeRunState(root, { ...state, delegations: { [stale.delegationId]: stale, [completed.delegationId]: completed } });
154
+ await appendEvent(root, state.runId, { event: 'delegation_started', runId: state.runId, data: { delegationId: stale.delegationId } });
155
+
156
+ const report = await doctor(root);
157
+
158
+ assert.equal(report.status, 'FAIL');
159
+ assert.equal(report.checks.some((check) => check.check === 'stale_delegation'), true);
160
+ assert.equal(report.checks.some((check) => check.check === 'terminal_event_missing'), true);
161
+ assert.equal(report.checks.some((check) => check.check === 'artifact_invalid'), true);
162
+ } finally {
163
+ await rm(root, { recursive: true, force: true });
164
+ }
165
+ });
166
+
167
+ test('archiveRun cancels running delegations and normal doctor skips archived evidence', async () => {
168
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-archive-run-'));
169
+ try {
170
+ await initProject(root);
171
+ const state = await createRun(root, { runId: 'run-1' });
172
+ const running = createDelegationRecord({
173
+ delegationId: 'D-T1-reviewer-001',
174
+ task: 'T1',
175
+ agent: 'reviewer',
176
+ expectedArtifact: 'artifacts/review-T1.md',
177
+ startedAt: '2020-01-01T00:00:00.000Z',
178
+ timeoutSeconds: 1
179
+ });
180
+ await writeRunState(root, { ...state, delegations: { [running.delegationId]: running } });
181
+ await appendEvent(root, state.runId, { event: 'delegation_started', runId: state.runId, data: { delegationId: running.delegationId } });
182
+
183
+ const archived = await archiveRun(root, state.runId, { reason: 'exploratory failure' });
184
+ const normalDoctor = await doctor(root);
185
+ const allRunsDoctor = await doctor(root, { allRuns: true });
186
+ const events = await readRunEvents(root, state.runId);
187
+
188
+ assert.equal(archived.status, 'archived');
189
+ assert.equal(archived.delegations[running.delegationId].status, 'CANCELLED');
190
+ assert.equal(events.some((event) => event.event === 'delegation_cancelled'), true);
191
+ assert.equal(events.some((event) => event.event === 'run_archived'), true);
192
+ assert.equal(normalDoctor.checks.some((check) => check.check === 'stale_delegation'), false);
193
+ assert.equal(normalDoctor.checks.some((check) => check.check === 'run_evidence_scope'), true);
194
+ assert.equal(allRunsDoctor.checks.some((check) => check.check === 'stale_delegation'), false);
195
+ } finally {
196
+ await rm(root, { recursive: true, force: true });
197
+ }
198
+ });
199
+
200
+ test('doctor latestOnly ignores older failed run evidence', async () => {
201
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-doctor-latest-only-'));
202
+ try {
203
+ await initProject(root);
204
+ const older = await createRun(root, { runId: 'run-older' });
205
+ const newer = await createRun(root, { runId: 'run-newer' });
206
+ const stale = createDelegationRecord({
207
+ delegationId: 'D-T1-reviewer-001',
208
+ task: 'T1',
209
+ agent: 'reviewer',
210
+ expectedArtifact: 'artifacts/review-T1.md',
211
+ startedAt: '2020-01-01T00:00:00.000Z',
212
+ timeoutSeconds: 1
213
+ });
214
+ await writeRunState(root, { ...older, updatedAt: '2026-05-01T00:00:00.000Z', delegations: { [stale.delegationId]: stale } });
215
+ await writeRunState(root, { ...newer, updatedAt: '2026-05-02T00:00:00.000Z' });
216
+ await appendEvent(root, older.runId, { event: 'delegation_started', runId: older.runId, data: { delegationId: stale.delegationId } });
217
+
218
+ const latestOnly = await doctor(root, { latestOnly: true });
219
+ const allRuns = await doctor(root, { allRuns: true });
220
+
221
+ assert.equal(latestOnly.checks.some((check) => check.check === 'stale_delegation'), false);
222
+ assert.equal(latestOnly.checks.some((check) => check.check === 'run_evidence_fast_path'), true);
223
+ assert.equal(allRuns.checks.some((check) => check.check === 'stale_delegation'), true);
224
+ } finally {
225
+ await rm(root, { recursive: true, force: true });
226
+ }
227
+ });
228
+
229
+ test('doctor trust suite flags mention-only acceptance and weak validator PASS artifacts', async () => {
230
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-doctor-trust-'));
231
+ try {
232
+ await initProject(root);
233
+ await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
234
+ const state = await createRun(root, { runId: 'run-1' });
235
+ await bindTestRunState(root, state.runId, 'feature', 'T1');
236
+ await writeArtifact(root, state.runId, 'validation-T1.md', validResultArtifact('validator', 'T1', 'PASS', 'artifacts/validation-T1.md'));
237
+ const restored = await readRunState(root, state.runId);
238
+ await writeRunState(root, {
239
+ ...restored,
240
+ status: 'completed',
241
+ validation: {
242
+ status: 'pass',
243
+ commands: ['npm test'],
244
+ evidence: ['artifacts/validation-T1.md']
245
+ },
246
+ tasks: {
247
+ T1: {
248
+ status: 'verified',
249
+ verifyStatus: 'PASS',
250
+ gaps: [],
251
+ artifacts: ['artifacts/validation-T1.md'],
252
+ acceptanceCoverage: [{ acceptance: 'AC-1', status: 'PASS', evidence: 'Mentioned in artifacts/validation-T1.md.' }]
253
+ }
254
+ },
255
+ artifacts: [{ path: 'artifacts/validation-T1.md', kind: 'validation', task: 'T1', agent: 'validator', createdAt: new Date().toISOString() }]
256
+ });
257
+
258
+ const report = await doctor(root, { allRuns: true, branch: 'feature' });
259
+
260
+ assert.equal(report.checks.some((check) => check.check === 'acceptance_trust' && check.level === 'FAIL'), true);
261
+ assert.equal(report.checks.some((check) => check.check === 'artifact_trust' && check.level === 'FAIL' && /UNSOURCED_PASS/.test(check.message)), true);
262
+ } finally {
263
+ await rm(root, { recursive: true, force: true });
264
+ }
265
+ });
266
+
267
+ test('doctor reports artifact ingestion state mismatch', async () => {
268
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-artifact-ingest-doctor-'));
269
+ try {
270
+ await initProject(root);
271
+ const state = await createRun(root, { runId: 'run-1' });
272
+ const delegation = createDelegationRecord({
273
+ delegationId: 'D-T1-reviewer-001',
274
+ task: 'T1',
275
+ agent: 'reviewer',
276
+ expectedArtifact: 'artifacts/review-T1.md'
277
+ });
278
+ await writeRunState(root, { ...state, delegations: { [delegation.delegationId]: delegation } });
279
+ await appendEvent(root, state.runId, { event: 'delegation_started', runId: state.runId, data: { delegationId: delegation.delegationId } });
280
+ await writeArtifact(root, state.runId, 'review-T1.md', `# Review
281
+
282
+ \`\`\`sdd-result
283
+ contract: sdd-result-v1
284
+ version: 1.3.0
285
+ agent: reviewer
286
+ task: T1
287
+ status: PASS
288
+ artifacts:
289
+ - artifacts/review-T1.md
290
+ \`\`\`
291
+ `);
292
+ const ingested = await ingestArtifactResult(root, state.runId, { delegationId: delegation.delegationId, artifactPath: 'artifacts/review-T1.md' });
293
+ const acceptedState = await readRunState(root, state.runId);
294
+ await writeRunState(root, {
295
+ ...acceptedState,
296
+ artifacts: [],
297
+ artifactIngestions: {
298
+ [`${delegation.delegationId}:artifacts/review-T1.md`]: ingested.record
299
+ }
300
+ });
301
+
302
+ const report = await doctor(root);
303
+
304
+ assert.equal(report.status, 'FAIL');
305
+ assert.equal(report.checks.some((check) => check.check === 'artifact_result_ingestion' && /missing from run artifact index/.test(check.message)), true);
306
+ } finally {
307
+ await rm(root, { recursive: true, force: true });
308
+ }
309
+ });
310
+
311
+ test('doctor honors explicit branch for document-chain scope', async () => {
312
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-doctor-branch-'));
313
+ try {
314
+ await initProject(root);
315
+ await execFileAsync('git', ['init'], { cwd: root });
316
+ await execFileAsync('git', ['checkout', '-b', 'other'], { cwd: root });
317
+
318
+ const report = await doctor(root, { latestOnly: true, branch: 'master' });
319
+
320
+ assert.equal(report.checks.some((check) => /Document chain skipped for other/.test(check.message)), false);
321
+ assert.equal(report.checks.some((check) => check.check.startsWith('document_chain')), true);
322
+ } finally {
323
+ await rm(root, { recursive: true, force: true });
324
+ }
325
+ });
326
+
327
+ test('doctor reports workflow handoff state diagnostics', async () => {
328
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-doctor-handoff-'));
329
+ try {
330
+ await initProject(root);
331
+ await recordStageRunProjection(root, doctorStageRun());
332
+ await recordWorkflowHandoffProjection(root, doctorHandoff());
333
+
334
+ const report = await doctor(root, { latestOnly: true, branch: 'master' });
335
+
336
+ assert.equal(report.checks.some((check) => check.check === 'workflow_handoff_state' && check.level === 'PASS' && /status=fresh/.test(check.message)), true);
337
+ assert.equal(report.checks.some((check) => check.check === 'workflow_handoff_state' && /do->test:accepted/.test(check.message)), true);
338
+ } finally {
339
+ await rm(root, { recursive: true, force: true });
340
+ }
341
+ });
342
+
343
+ test('doctor reports context offload and subagent dispatch state diagnostics', async () => {
344
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-doctor-context-subagent-'));
345
+ try {
346
+ await initProject(root);
347
+ const signal = evaluateContextLoadSignal({
348
+ scope: doctorScope,
349
+ refs: [{ kind: 'document', ref: 'specs/master/tasks.md' }],
350
+ fileCount: 20,
351
+ artifactBytes: 200_000,
352
+ dependencyFanout: 12,
353
+ unknownImpact: true,
354
+ generatedAt: '2026-05-18T00:00:00.000Z'
355
+ });
356
+ await recordContextLoadSignalProjection(root, signal);
357
+ await recordContextOffloadDecisionProjection(root, decideContextOffload(signal, { dispatchRefs: [{ kind: 'projection', ref: 'phase8_subagent_dispatch:master:T1:run-1:none:dispatch-1' }] }));
358
+ await recordSubagentDispatchProjection(root, doctorSubagentDispatch());
359
+
360
+ const report = await doctor(root, { latestOnly: true, branch: 'master' });
361
+
362
+ assert.equal(report.checks.some((check) => check.check === 'context_offload_state' && check.level === 'PASS' && /level=high action=dispatch-subagent/.test(check.message)), true);
363
+ assert.equal(report.checks.some((check) => check.check === 'subagent_dispatch_state' && check.level === 'FAIL' && /status=blocked/.test(check.message)), true);
364
+ } finally {
365
+ await rm(root, { recursive: true, force: true });
366
+ }
367
+ });
368
+
369
+ test('archived failed subagent dispatch no longer blocks doctor diagnostics', async () => {
370
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-doctor-archived-subagent-'));
371
+ try {
372
+ await initProject(root);
373
+ await createRun(root, { runId: 'run-1' });
374
+ await recordSubagentDispatchProjection(root, {
375
+ ...doctorSubagentDispatch(),
376
+ status: 'failed',
377
+ updatedAt: '2026-05-18T00:02:00.000Z'
378
+ });
379
+ const failed = await doctor(root, { latestOnly: true, branch: 'master' });
380
+ assert.equal(failed.checks.some((check) => check.check === 'subagent_dispatch_state' && check.level === 'FAIL' && /status=failed/.test(check.message)), true);
381
+
382
+ await archiveRun(root, 'run-1', { reason: 'failed subagent superseded by rerun' });
383
+ const recovered = await doctor(root, { latestOnly: true, branch: 'master' });
384
+
385
+ assert.equal(recovered.checks.some((check) => check.check === 'subagent_dispatch_state' && check.level === 'PASS' && /status=missing/.test(check.message)), true);
386
+ } finally {
387
+ await rm(root, { recursive: true, force: true });
388
+ }
389
+ });
390
+
391
+ test('doctor reports unavailable Phase 8 runtime checks as warnings', async () => {
392
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-doctor-runtime-unavailable-'));
393
+ try {
394
+ await initProject(root);
395
+ await withRuntimeStore(root, ({ db }) => {
396
+ db.prepare('INSERT INTO projections (projection_id, projection_type, scope_key, generated_at, payload_json) VALUES (?, ?, ?, ?, ?)')
397
+ .run('bad-context-build', 'context_build', 'master:T1:run-1:none', new Date().toISOString(), '{');
398
+ });
399
+
400
+ const report = await doctor(root, { latestOnly: true, branch: 'master' });
401
+
402
+ assert.equal(report.checks.some((check) => check.check === 'lifecycle_risk_decision' && check.level === 'WARN' && /unavailable/.test(check.message)), true);
403
+ assert.equal(report.checks.some((check) => check.check === 'workflow_handoff_state' && check.level === 'WARN' && /unavailable/.test(check.message)), true);
404
+ assert.equal(report.checks.some((check) => check.check === 'context_offload_state' && check.level === 'WARN' && /unavailable/.test(check.message)), true);
405
+ assert.equal(report.checks.some((check) => check.check === 'subagent_dispatch_state' && check.level === 'WARN' && /unavailable/.test(check.message)), true);
406
+ } finally {
407
+ await rm(root, { recursive: true, force: true });
408
+ }
409
+ });
410
+
411
+ test('Phase 8.9 surfaces capability health in status, doctor, and ship gates', async () => {
412
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-capability-health-'));
413
+ try {
414
+ await initProject(root);
415
+ await writeBranchDocs(root, 'master', capabilityHealthTaskMarkdown('SECURITY'));
416
+
417
+ const status = await getProjectStatus(root, { branch: 'master' });
418
+ const report = await doctor(root, { latestOnly: true, branch: 'master' });
419
+ const ship = await runShip(root, { branch: 'master', dryRun: true });
420
+ const doctorCheck = report.checks.find((check) => check.check === 'capability_health');
421
+
422
+ assert.equal(status.capabilityHealth.status, 'warn');
423
+ assert.equal(status.capabilityHealth.missingBaselineDomains.length, 0);
424
+ assert.equal(status.capabilityHealth.sources.quarantined > 0, true);
425
+ assert.equal(status.capabilityHealth.sources.denied > 0, true);
426
+ assert.deepEqual(status.capabilityHealth.releaseCriticalGaps, ['security-engineering']);
427
+ assert.equal(status.capabilityHealth.warnings.some((warning) => /release-critical capability gap security-engineering/.test(warning)), true);
428
+ assert.equal(doctorCheck?.level, 'WARN');
429
+ assert.match(doctorCheck?.message ?? '', /release_critical_gaps=security-engineering/);
430
+ assert.deepEqual(ship.projectStatus.capabilityHealth.releaseCriticalGaps, ['security-engineering']);
431
+ } finally {
432
+ await rm(root, { recursive: true, force: true });
433
+ }
434
+ });
435
+
436
+ test('ship reports token pressure as diagnostic pass', async () => {
437
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-ship-token-diagnostic-'));
438
+ try {
439
+ await initProject(root);
440
+ await withRuntimeStore(root, ({ db }) => {
441
+ db.prepare('INSERT INTO projections (projection_id, projection_type, scope_key, generated_at, payload_json) VALUES (?, ?, ?, ?, ?)')
442
+ .run('context-build-pressure', 'context_build', 'master:T1:run-1:none', '2026-05-18T00:00:00.000Z', JSON.stringify({
443
+ taskId: 'T1',
444
+ profile: 'normal',
445
+ budget: { estimatedBytes: 900, maxBytes: 1000, estimatedTokens: 225 }
446
+ }));
447
+ });
448
+
449
+ const ship = await runShip(root, { branch: 'master', dryRun: true });
450
+
451
+ assert.equal(ship.projectStatus.tokenProjection.health, 'pressure');
452
+ } finally {
453
+ await rm(root, { recursive: true, force: true });
454
+ }
455
+ });
456
+
457
+ test.skip('ship accepts validated runs without requiring sync-back apply', async () => {
458
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-ship-syncback-not-required-'));
459
+ try {
460
+ await initProject(root);
461
+ await writeBranchDocs(root, 'master', validTaskMarkdown('T1', []));
462
+ const state = await createRun(root, { runId: 'run-1' });
463
+ await bindTestRunState(root, state.runId, 'master', 'T1');
464
+ const bound = await readRunState(root, state.runId);
465
+ await writeRunState(root, {
466
+ ...bound,
467
+ status: 'completed',
468
+ validation: {
469
+ status: 'pass',
470
+ commands: ['npm test'],
471
+ evidence: []
472
+ }
473
+ });
474
+
475
+ const ship = await runShip(root, { branch: 'master', dryRun: true });
476
+ const latestRunCheck = ship.checks.find((check) => check.name === 'latest_run');
477
+
478
+ assert.equal(latestRunCheck?.status, 'PASS');
479
+ assert.match(latestRunCheck?.message ?? '', /sync_back=not_created/);
480
+ } finally {
481
+ await rm(root, { recursive: true, force: true });
482
+ }
483
+ });
484
+
485
+ test.skip('doctor reports Phase 8.18 compatibility and Phase 9 readiness diagnostics', async () => {
486
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-phase818-doctor-'));
487
+ try {
488
+ await initProject(root);
489
+ await writeBranchDocs(root, 'master', validTaskMarkdown('T1', []));
490
+ const state = await createRun(root, { runId: 'run-1', branch: 'master', taskId: 'T1' });
491
+ await writeArtifact(root, state.runId, 'review-T1.md', validResultArtifact('reviewer', 'T1', 'PASS', 'artifacts/review-T1.md'));
492
+ const legacyRunDir = path.join(root, '.sdd', 'runs', state.runId);
493
+ await mkdir(path.join(legacyRunDir, 'agent-executions'), { recursive: true });
494
+ await writeFile(path.join(legacyRunDir, 'state.json'), '{}', 'utf8');
495
+ await writeFile(path.join(legacyRunDir, 'events.jsonl'), '{}\n', 'utf8');
496
+ await writeFile(path.join(legacyRunDir, 'invocations.jsonl'), '{}\n', 'utf8');
497
+ await writeFile(path.join(legacyRunDir, 'agent-executions', 'legacy.json'), '{}', 'utf8');
498
+
499
+ const report = await doctor(root, { allRuns: true, branch: 'master' });
500
+
501
+ const legacyRunFiles = report.checks.find((check) => check.check === 'phase8_18_legacy_run_files');
502
+ assert.equal(legacyRunFiles?.level, 'WARN');
503
+ assert.match(legacyRunFiles?.message ?? '', /run-1:state\.json/);
504
+ assert.match(legacyRunFiles?.message ?? '', /run-1:events\.jsonl/);
505
+ assert.match(legacyRunFiles?.message ?? '', /run-1:invocations\.jsonl/);
506
+ assert.doesNotMatch(legacyRunFiles?.message ?? '', /evidence/);
507
+ assert.equal(report.checks.some((check) => check.check === 'phase8_18_legacy_sidecars' && check.level === 'WARN' && /run-1/.test(check.message)), true);
508
+ assert.equal(report.checks.some((check) => check.check === 'phase9_readiness' && check.level === 'PASS' && /optional_advisory_only/.test(check.message)), true);
509
+ } finally {
510
+ await rm(root, { recursive: true, force: true });
511
+ }
512
+ });
513
+
514
+ test('ship blocks context offload curation through doctor gate', async () => {
515
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-ship-context-curation-'));
516
+ try {
517
+ await initProject(root);
518
+ const signal = evaluateContextLoadSignal({
519
+ scope: doctorScope,
520
+ fileCount: 50,
521
+ artifactBytes: 600_000,
522
+ dependencyFanout: 30,
523
+ unknownImpact: true,
524
+ generatedAt: '2026-05-18T00:00:00.000Z'
525
+ });
526
+ await recordContextLoadSignalProjection(root, signal);
527
+ await recordContextOffloadDecisionProjection(root, decideContextOffload(signal));
528
+
529
+ const ship = await runShip(root, { branch: 'master', dryRun: true });
530
+ const doctorFastCheck = ship.checks.find((check) => check.name === 'doctor_fast');
531
+
532
+ assert.equal(ship.status, 'BLOCKED');
533
+ assert.equal(doctorFastCheck?.status, 'BLOCKED');
534
+ assert.match(doctorFastCheck?.message ?? '', /doctor_status=FAIL/);
535
+ assert.equal(ship.nextActions.some((action) => /sdd doctor fast --branch master/.test(action)), true);
536
+ } finally {
537
+ await rm(root, { recursive: true, force: true });
538
+ }
539
+ });
540
+
541
+ function capabilityHealthTaskMarkdown(taskId: string): string {
542
+ return `# Tasks
543
+
544
+ ### ${taskId}: Security readiness task
545
+
546
+ \`\`\`sdd-task
547
+ id: ${taskId}
548
+ status: pending
549
+ wave: 1
550
+ depends_on: []
551
+ acceptance_refs:
552
+ - AC-1
553
+ affected_files:
554
+ - packages/core/src/auth.ts
555
+ validation:
556
+ - npm test
557
+ risk:
558
+ - security
559
+ \`\`\`
560
+
561
+ #### Boundary
562
+
563
+ Stay inside security readiness fixtures.
564
+
565
+ #### Acceptance
566
+
567
+ - AC-1: Security readiness is covered.
568
+ `;
569
+ }
570
+
571
+ const doctorScope: RuntimeScope = { branch: 'master', taskId: 'T1', runId: 'run-1' };
572
+
573
+ function doctorStageRun(): StageRun {
574
+ return {
575
+ contract: STAGE_RUN_CONTRACT_VERSION,
576
+ id: 'doctor-stage-do',
577
+ scope: doctorScope,
578
+ stage: 'do',
579
+ ownerAgent: 'implementer',
580
+ coMainAgents: ['reviewer'],
581
+ status: 'completed',
582
+ inputRefs: [{ kind: 'projection', ref: 'phase8_lifecycle_risk_decision:master:T1:run-1:none' }],
583
+ outputRefs: [{ kind: 'artifact', ref: 'artifacts/doctor-handoff.md' }],
584
+ decisionRefs: [{ kind: 'projection', ref: 'phase8_lifecycle_risk_decision:master:T1:run-1:none' }],
585
+ blockingReasons: [],
586
+ createdAt: '2026-05-18T00:00:00.000Z',
587
+ updatedAt: '2026-05-18T00:01:00.000Z'
588
+ };
589
+ }
590
+
591
+ function doctorHandoff(): WorkflowHandoff {
592
+ return {
593
+ contract: WORKFLOW_HANDOFF_CONTRACT_VERSION,
594
+ id: 'doctor-handoff-do-test',
595
+ scope: doctorScope,
596
+ fromStage: 'do',
597
+ toStage: 'test',
598
+ fromAgent: 'implementer',
599
+ toAgent: 'validator',
600
+ status: 'accepted',
601
+ outputRefs: [{ kind: 'artifact', ref: 'artifacts/doctor-handoff.md' }],
602
+ requiredInputRefs: [{ kind: 'projection', ref: 'phase8_lifecycle_risk_decision:master:T1:run-1:none' }],
603
+ riskDecisionRef: { kind: 'projection', ref: 'phase8_lifecycle_risk_decision:master:T1:run-1:none' },
604
+ evidenceRefs: [{ kind: 'evidence', ref: 'artifacts/doctor-handoff-validation.md#AC-1' }],
605
+ openQuestions: [],
606
+ blockingGaps: [],
607
+ createdAt: '2026-05-18T00:02:00.000Z',
608
+ decidedAt: '2026-05-18T00:03:00.000Z'
609
+ };
610
+ }
611
+
612
+ function doctorSubagentDispatch(): SubagentDispatch {
613
+ return {
614
+ contract: SUBAGENT_DISPATCH_CONTRACT_VERSION,
615
+ id: 'dispatch-1',
616
+ scope: doctorScope,
617
+ workUnitId: 'wu-subagent-1',
618
+ definitionName: 'test-writer',
619
+ mode: 'background',
620
+ status: 'queued',
621
+ blocking: true,
622
+ requiredBefore: 'handoff',
623
+ contextRef: { kind: 'projection', ref: 'sdd-scoped-context-handoff:T1' },
624
+ createdAt: '2026-05-18T00:00:00.000Z',
625
+ updatedAt: '2026-05-18T00:01:00.000Z'
626
+ };
627
+ }