sdd-agent-platform 0.4.2 → 0.5.1

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 (834) hide show
  1. package/README.md +34 -41
  2. package/node_modules/@sdd-agent-platform/core/dist/ai-tools.js +56 -73
  3. package/node_modules/@sdd-agent-platform/core/dist/ai-tools.js.map +1 -1
  4. package/node_modules/@sdd-agent-platform/core/dist/artifacts/ingestion.js +9 -64
  5. package/node_modules/@sdd-agent-platform/core/dist/artifacts/ingestion.js.map +1 -1
  6. package/node_modules/@sdd-agent-platform/core/dist/artifacts/sdd-evidence.js +1 -1
  7. package/node_modules/@sdd-agent-platform/core/dist/artifacts/sdd-evidence.js.map +1 -1
  8. package/node_modules/@sdd-agent-platform/core/dist/artifacts/sdd-result.js +17 -26
  9. package/node_modules/@sdd-agent-platform/core/dist/artifacts/sdd-result.js.map +1 -1
  10. package/node_modules/@sdd-agent-platform/core/dist/config/init-project.d.ts +8 -7
  11. package/node_modules/@sdd-agent-platform/core/dist/config/init-project.js +8 -12
  12. package/node_modules/@sdd-agent-platform/core/dist/config/init-project.js.map +1 -1
  13. package/node_modules/@sdd-agent-platform/core/dist/config/project-config.d.ts +1 -1
  14. package/node_modules/@sdd-agent-platform/core/dist/config/project-config.js +1 -1
  15. package/node_modules/@sdd-agent-platform/core/dist/config/project-config.js.map +1 -1
  16. package/node_modules/@sdd-agent-platform/core/dist/config/starter-documents.d.ts +3 -4
  17. package/node_modules/@sdd-agent-platform/core/dist/config/starter-documents.js +377 -411
  18. package/node_modules/@sdd-agent-platform/core/dist/config/starter-documents.js.map +1 -1
  19. package/node_modules/@sdd-agent-platform/core/dist/context/build-package.d.ts +1 -1
  20. package/node_modules/@sdd-agent-platform/core/dist/context/build-package.js +18 -25
  21. package/node_modules/@sdd-agent-platform/core/dist/context/build-package.js.map +1 -1
  22. package/node_modules/@sdd-agent-platform/core/dist/context/evidence-summary.js +8 -26
  23. package/node_modules/@sdd-agent-platform/core/dist/context/evidence-summary.js.map +1 -1
  24. package/node_modules/@sdd-agent-platform/core/dist/context/log-worker.js +2 -2
  25. package/node_modules/@sdd-agent-platform/core/dist/context/log-worker.js.map +1 -1
  26. package/node_modules/@sdd-agent-platform/core/dist/context-offload/contracts.d.ts +1 -1
  27. package/node_modules/@sdd-agent-platform/core/dist/contracts.d.ts +6 -1
  28. package/node_modules/@sdd-agent-platform/core/dist/contracts.js +5 -0
  29. package/node_modules/@sdd-agent-platform/core/dist/contracts.js.map +1 -1
  30. package/node_modules/@sdd-agent-platform/core/dist/delegation/model.d.ts +0 -3
  31. package/node_modules/@sdd-agent-platform/core/dist/delegation/validation.d.ts +0 -3
  32. package/node_modules/@sdd-agent-platform/core/dist/delegation/validation.js +4 -7
  33. package/node_modules/@sdd-agent-platform/core/dist/delegation/validation.js.map +1 -1
  34. package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/document-chain.js +3 -13
  35. package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/document-chain.js.map +1 -1
  36. package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/local-run-index.js +1 -9
  37. package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/local-run-index.js.map +1 -1
  38. package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/project.js +9 -9
  39. package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/project.js.map +1 -1
  40. package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/registries.js +1 -0
  41. package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/registries.js.map +1 -1
  42. package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/run-evidence.js +4 -4
  43. package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/run-evidence.js.map +1 -1
  44. package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/run-trust.js +24 -0
  45. package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/run-trust.js.map +1 -1
  46. package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/runtime-contracts.js +2 -2
  47. package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/runtime-contracts.js.map +1 -1
  48. package/node_modules/@sdd-agent-platform/core/dist/doctor/doctor.js +43 -180
  49. package/node_modules/@sdd-agent-platform/core/dist/doctor/doctor.js.map +1 -1
  50. package/node_modules/@sdd-agent-platform/core/dist/evidence/lookup.d.ts +1 -1
  51. package/node_modules/@sdd-agent-platform/core/dist/evidence/lookup.js +7 -14
  52. package/node_modules/@sdd-agent-platform/core/dist/evidence/lookup.js.map +1 -1
  53. package/node_modules/@sdd-agent-platform/core/dist/evidence-runtime/coordination.js +110 -0
  54. package/node_modules/@sdd-agent-platform/core/dist/evidence-runtime/coordination.js.map +1 -0
  55. package/node_modules/@sdd-agent-platform/core/dist/execution/background-executor.js +4 -4
  56. package/node_modules/@sdd-agent-platform/core/dist/execution/background-executor.js.map +1 -1
  57. package/node_modules/@sdd-agent-platform/core/dist/execution/foreground-subagents.js +3 -3
  58. package/node_modules/@sdd-agent-platform/core/dist/execution/foreground-subagents.js.map +1 -1
  59. package/node_modules/@sdd-agent-platform/core/dist/execution/host-invocation.js +85 -86
  60. package/node_modules/@sdd-agent-platform/core/dist/execution/host-invocation.js.map +1 -1
  61. package/node_modules/@sdd-agent-platform/core/dist/execution/resident-worker.js +2 -3
  62. package/node_modules/@sdd-agent-platform/core/dist/execution/resident-worker.js.map +1 -1
  63. package/node_modules/@sdd-agent-platform/core/dist/execution/stage-team-runtime.js +2 -2
  64. package/node_modules/@sdd-agent-platform/core/dist/execution/stage-team-runtime.js.map +1 -1
  65. package/node_modules/@sdd-agent-platform/core/dist/governance/policy.d.ts +1 -1
  66. package/node_modules/@sdd-agent-platform/core/dist/governance/policy.js +1 -1
  67. package/node_modules/@sdd-agent-platform/core/dist/governance/policy.js.map +1 -1
  68. package/node_modules/@sdd-agent-platform/core/dist/instructions.d.ts +1 -1
  69. package/node_modules/@sdd-agent-platform/core/dist/instructions.js +31 -67
  70. package/node_modules/@sdd-agent-platform/core/dist/instructions.js.map +1 -1
  71. package/node_modules/@sdd-agent-platform/core/dist/lifecycle/decision-gate.js +1 -1
  72. package/node_modules/@sdd-agent-platform/core/dist/lifecycle/decision-gate.js.map +1 -1
  73. package/node_modules/@sdd-agent-platform/core/dist/lifecycle/ship.d.ts +0 -1
  74. package/node_modules/@sdd-agent-platform/core/dist/lifecycle/ship.js +59 -85
  75. package/node_modules/@sdd-agent-platform/core/dist/lifecycle/ship.js.map +1 -1
  76. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/contracts.d.ts +159 -0
  77. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/contracts.js +7 -0
  78. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/contracts.js.map +1 -0
  79. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/kernel.d.ts +16 -0
  80. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/kernel.js +461 -0
  81. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/kernel.js.map +1 -0
  82. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph.d.ts +2 -0
  83. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph.js +3 -0
  84. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph.js.map +1 -0
  85. package/node_modules/@sdd-agent-platform/core/dist/orchestration/contracts.d.ts +1 -1
  86. package/node_modules/@sdd-agent-platform/core/dist/orchestration/runtime.d.ts +2 -12
  87. package/node_modules/@sdd-agent-platform/core/dist/orchestration/runtime.js +32 -80
  88. package/node_modules/@sdd-agent-platform/core/dist/orchestration/runtime.js.map +1 -1
  89. package/node_modules/@sdd-agent-platform/core/dist/registries/agent-capability-catalog.d.ts +2 -5
  90. package/node_modules/@sdd-agent-platform/core/dist/registries/agent-capability-catalog.js +27 -69
  91. package/node_modules/@sdd-agent-platform/core/dist/registries/agent-capability-catalog.js.map +1 -1
  92. package/node_modules/@sdd-agent-platform/core/dist/registries/agent-registry.js +118 -34
  93. package/node_modules/@sdd-agent-platform/core/dist/registries/agent-registry.js.map +1 -1
  94. package/node_modules/@sdd-agent-platform/core/dist/registries/agent-runtime-static.js +1 -1
  95. package/node_modules/@sdd-agent-platform/core/dist/registries/agent-runtime-static.js.map +1 -1
  96. package/node_modules/@sdd-agent-platform/core/dist/registries/capability-sources.js +1 -1
  97. package/node_modules/@sdd-agent-platform/core/dist/registries/command-team-runtime.d.ts +1 -1
  98. package/node_modules/@sdd-agent-platform/core/dist/registries/command-team-runtime.js +8 -15
  99. package/node_modules/@sdd-agent-platform/core/dist/registries/command-team-runtime.js.map +1 -1
  100. package/node_modules/@sdd-agent-platform/core/dist/registries/eval-learning-context.js +4 -4
  101. package/node_modules/@sdd-agent-platform/core/dist/registries/eval-learning-context.js.map +1 -1
  102. package/node_modules/@sdd-agent-platform/core/dist/registries/plan-scout-domains.d.ts +13 -0
  103. package/node_modules/@sdd-agent-platform/core/dist/registries/plan-scout-domains.js +76 -0
  104. package/node_modules/@sdd-agent-platform/core/dist/registries/plan-scout-domains.js.map +1 -0
  105. package/node_modules/@sdd-agent-platform/core/dist/registries/query-status.js +2 -2
  106. package/node_modules/@sdd-agent-platform/core/dist/registries/query-status.js.map +1 -1
  107. package/node_modules/@sdd-agent-platform/core/dist/registries/skill-capabilities.js +7 -7
  108. package/node_modules/@sdd-agent-platform/core/dist/registries/skill-capabilities.js.map +1 -1
  109. package/node_modules/@sdd-agent-platform/core/dist/registries/tool-capabilities.js +4 -4
  110. package/node_modules/@sdd-agent-platform/core/dist/registries/tool-capabilities.js.map +1 -1
  111. package/node_modules/@sdd-agent-platform/core/dist/registries/tool-plugins.js +2 -2
  112. package/node_modules/@sdd-agent-platform/core/dist/registries/tool-plugins.js.map +1 -1
  113. package/node_modules/@sdd-agent-platform/core/dist/registries/worker-adapters.js +11 -11
  114. package/node_modules/@sdd-agent-platform/core/dist/registries/worker-adapters.js.map +1 -1
  115. package/node_modules/@sdd-agent-platform/core/dist/registries/workflow-gates.d.ts +1 -1
  116. package/node_modules/@sdd-agent-platform/core/dist/registries/workflow-gates.js +21 -21
  117. package/node_modules/@sdd-agent-platform/core/dist/registries/workflow-gates.js.map +1 -1
  118. package/node_modules/@sdd-agent-platform/core/dist/risk/consumer-diagnostics.js +2 -1
  119. package/node_modules/@sdd-agent-platform/core/dist/risk/consumer-diagnostics.js.map +1 -1
  120. package/node_modules/@sdd-agent-platform/core/dist/risk/kernel.js +6 -6
  121. package/node_modules/@sdd-agent-platform/core/dist/risk/kernel.js.map +1 -1
  122. package/node_modules/@sdd-agent-platform/core/dist/risk/legacy-adapters.js +11 -23
  123. package/node_modules/@sdd-agent-platform/core/dist/risk/legacy-adapters.js.map +1 -1
  124. package/node_modules/@sdd-agent-platform/core/dist/risk/workflow-gates.d.ts +2 -2
  125. package/node_modules/@sdd-agent-platform/core/dist/risk/workflow-gates.js +18 -20
  126. package/node_modules/@sdd-agent-platform/core/dist/risk/workflow-gates.js.map +1 -1
  127. package/node_modules/@sdd-agent-platform/core/dist/router/agent-runtime.d.ts +0 -2
  128. package/node_modules/@sdd-agent-platform/core/dist/router/route-projection.js +1 -1
  129. package/node_modules/@sdd-agent-platform/core/dist/router/route-projection.js.map +1 -1
  130. package/node_modules/@sdd-agent-platform/core/dist/router/routing.js +16 -48
  131. package/node_modules/@sdd-agent-platform/core/dist/router/routing.js.map +1 -1
  132. package/node_modules/@sdd-agent-platform/core/dist/router/runtime-import.js +11 -1
  133. package/node_modules/@sdd-agent-platform/core/dist/router/runtime-import.js.map +1 -1
  134. package/node_modules/@sdd-agent-platform/core/dist/router/runtime-validation.js +2 -2
  135. package/node_modules/@sdd-agent-platform/core/dist/router/runtime-validation.js.map +1 -1
  136. package/node_modules/@sdd-agent-platform/core/dist/router/stage-route-binding.d.ts +2 -2
  137. package/node_modules/@sdd-agent-platform/core/dist/router/stage-route-binding.js +20 -28
  138. package/node_modules/@sdd-agent-platform/core/dist/router/stage-route-binding.js.map +1 -1
  139. package/node_modules/@sdd-agent-platform/core/dist/router.d.ts +0 -1
  140. package/node_modules/@sdd-agent-platform/core/dist/router.js +0 -1
  141. package/node_modules/@sdd-agent-platform/core/dist/router.js.map +1 -1
  142. package/node_modules/@sdd-agent-platform/core/dist/run-state/artifacts.d.ts +6 -6
  143. package/node_modules/@sdd-agent-platform/core/dist/run-state/artifacts.js +13 -124
  144. package/node_modules/@sdd-agent-platform/core/dist/run-state/artifacts.js.map +1 -1
  145. package/node_modules/@sdd-agent-platform/core/dist/run-state/inspect-run.d.ts +2 -0
  146. package/node_modules/@sdd-agent-platform/core/dist/run-state/inspect-run.js +5 -7
  147. package/node_modules/@sdd-agent-platform/core/dist/run-state/inspect-run.js.map +1 -1
  148. package/node_modules/@sdd-agent-platform/core/dist/run-state/model.d.ts +28 -28
  149. package/node_modules/@sdd-agent-platform/core/dist/run-state/run-index.d.ts +3 -2
  150. package/node_modules/@sdd-agent-platform/core/dist/run-state/run-index.js +15 -66
  151. package/node_modules/@sdd-agent-platform/core/dist/run-state/run-index.js.map +1 -1
  152. package/node_modules/@sdd-agent-platform/core/dist/run-state/run-state.js +26 -36
  153. package/node_modules/@sdd-agent-platform/core/dist/run-state/run-state.js.map +1 -1
  154. package/node_modules/@sdd-agent-platform/core/dist/run-state/task-evidence.d.ts +0 -4
  155. package/node_modules/@sdd-agent-platform/core/dist/run-state/task-evidence.js +5 -51
  156. package/node_modules/@sdd-agent-platform/core/dist/run-state/task-evidence.js.map +1 -1
  157. package/node_modules/@sdd-agent-platform/core/dist/run-state.d.ts +0 -1
  158. package/node_modules/@sdd-agent-platform/core/dist/run-state.js +0 -1
  159. package/node_modules/@sdd-agent-platform/core/dist/run-state.js.map +1 -1
  160. package/node_modules/@sdd-agent-platform/core/dist/runtime-analysis/build.js +1 -1
  161. package/node_modules/@sdd-agent-platform/core/dist/runtime-analysis/build.js.map +1 -1
  162. package/node_modules/@sdd-agent-platform/core/dist/runtime-analysis/findings.js +7 -16
  163. package/node_modules/@sdd-agent-platform/core/dist/runtime-analysis/findings.js.map +1 -1
  164. package/node_modules/@sdd-agent-platform/core/dist/runtime-analysis/model.d.ts +1 -2
  165. package/node_modules/@sdd-agent-platform/core/dist/runtime-paths.d.ts +0 -1
  166. package/node_modules/@sdd-agent-platform/core/dist/runtime-paths.js +1 -4
  167. package/node_modules/@sdd-agent-platform/core/dist/runtime-paths.js.map +1 -1
  168. package/node_modules/@sdd-agent-platform/core/dist/runtime-projection-p0.d.ts +2 -2
  169. package/node_modules/@sdd-agent-platform/core/dist/runtime-projection-p0.js +11 -0
  170. package/node_modules/@sdd-agent-platform/core/dist/runtime-projection-p0.js.map +1 -1
  171. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/artifact-depth.d.ts +14 -0
  172. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/artifact-depth.js +179 -0
  173. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/artifact-depth.js.map +1 -0
  174. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/document-hashes.d.ts +0 -2
  175. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/document-hashes.js +10 -97
  176. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/document-hashes.js.map +1 -1
  177. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/run-binding.d.ts +1 -1
  178. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/run-binding.js +6 -8
  179. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/run-binding.js.map +1 -1
  180. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-parser.d.ts +5 -2
  181. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-parser.js +85 -68
  182. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-parser.js.map +1 -1
  183. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-rendering.js +2 -2
  184. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-rendering.js.map +1 -1
  185. package/node_modules/@sdd-agent-platform/core/dist/spec-entry.js +40 -0
  186. package/node_modules/@sdd-agent-platform/core/dist/spec-entry.js.map +1 -0
  187. package/node_modules/@sdd-agent-platform/core/dist/spec-manager-contracts.d.ts +12 -0
  188. package/node_modules/@sdd-agent-platform/core/dist/spec-manager-contracts.js +2 -0
  189. package/node_modules/@sdd-agent-platform/core/dist/spec-manager-contracts.js.map +1 -0
  190. package/node_modules/@sdd-agent-platform/core/dist/stage-artifacts.d.ts +2 -2
  191. package/node_modules/@sdd-agent-platform/core/dist/stage-artifacts.js +19 -26
  192. package/node_modules/@sdd-agent-platform/core/dist/stage-artifacts.js.map +1 -1
  193. package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration-contracts.d.ts +1 -1
  194. package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration-contracts.js +3 -6
  195. package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration-contracts.js.map +1 -1
  196. package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration.d.ts +111 -263
  197. package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration.js +1272 -1124
  198. package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration.js.map +1 -1
  199. package/node_modules/@sdd-agent-platform/core/dist/stage-runtime/runtime.js +5 -5
  200. package/node_modules/@sdd-agent-platform/core/dist/stage-runtime/runtime.js.map +1 -1
  201. package/node_modules/@sdd-agent-platform/core/dist/status/project-status.d.ts +1 -44
  202. package/node_modules/@sdd-agent-platform/core/dist/status/project-status.js +47 -170
  203. package/node_modules/@sdd-agent-platform/core/dist/status/project-status.js.map +1 -1
  204. package/node_modules/@sdd-agent-platform/core/dist/storage/runtime-store.js +73 -73
  205. package/node_modules/@sdd-agent-platform/core/dist/subagents/contracts.d.ts +1 -1
  206. package/node_modules/@sdd-agent-platform/core/dist/subagents/runtime.js +7 -7
  207. package/node_modules/@sdd-agent-platform/core/dist/subagents/runtime.js.map +1 -1
  208. package/node_modules/@sdd-agent-platform/core/dist/sync-back/apply.d.ts +1 -0
  209. package/node_modules/@sdd-agent-platform/core/dist/sync-back/apply.js +2 -0
  210. package/node_modules/@sdd-agent-platform/core/dist/sync-back/apply.js.map +1 -0
  211. package/node_modules/@sdd-agent-platform/core/dist/sync-back/inspect.d.ts +1 -0
  212. package/node_modules/@sdd-agent-platform/core/dist/sync-back/inspect.js +2 -0
  213. package/node_modules/@sdd-agent-platform/core/dist/sync-back/inspect.js.map +1 -0
  214. package/node_modules/@sdd-agent-platform/core/dist/sync-back.d.ts +1 -0
  215. package/node_modules/@sdd-agent-platform/core/dist/sync-back.js +2 -0
  216. package/node_modules/@sdd-agent-platform/core/dist/sync-back.js.map +1 -0
  217. package/node_modules/@sdd-agent-platform/core/dist/task-execution-contract.d.ts +167 -0
  218. package/node_modules/@sdd-agent-platform/core/dist/task-execution-contract.js +377 -0
  219. package/node_modules/@sdd-agent-platform/core/dist/task-execution-contract.js.map +1 -0
  220. package/node_modules/@sdd-agent-platform/core/dist/test-support/fixtures.js +329 -314
  221. package/node_modules/@sdd-agent-platform/core/dist/test-support/fixtures.js.map +1 -1
  222. package/node_modules/@sdd-agent-platform/core/dist/test-support/run-state.d.ts +1 -0
  223. package/node_modules/@sdd-agent-platform/core/dist/test-support/run-state.js +53 -7
  224. package/node_modules/@sdd-agent-platform/core/dist/test-support/run-state.js.map +1 -1
  225. package/node_modules/@sdd-agent-platform/core/dist/truth-reconciliation.js +9 -12
  226. package/node_modules/@sdd-agent-platform/core/dist/truth-reconciliation.js.map +1 -1
  227. package/node_modules/@sdd-agent-platform/core/dist/tsconfig.tsbuildinfo +1 -1
  228. package/node_modules/@sdd-agent-platform/core/dist/verification/goal-verify.d.ts +0 -48
  229. package/node_modules/@sdd-agent-platform/core/dist/verification/goal-verify.js +1 -520
  230. package/node_modules/@sdd-agent-platform/core/dist/verification/goal-verify.js.map +1 -1
  231. package/node_modules/@sdd-agent-platform/core/dist/verification/rendering.d.ts +5 -5
  232. package/node_modules/@sdd-agent-platform/core/dist/verification/rendering.js +14 -14
  233. package/node_modules/@sdd-agent-platform/core/dist/verification/rendering.js.map +1 -1
  234. package/node_modules/@sdd-agent-platform/core/dist/verification/single-task-loop.d.ts +1 -0
  235. package/node_modules/@sdd-agent-platform/core/dist/verification/single-task-loop.js +111 -159
  236. package/node_modules/@sdd-agent-platform/core/dist/verification/single-task-loop.js.map +1 -1
  237. package/node_modules/@sdd-agent-platform/core/dist/verification/task-evidence-judgment.d.ts +49 -0
  238. package/node_modules/@sdd-agent-platform/core/dist/verification/task-evidence-judgment.js +521 -0
  239. package/node_modules/@sdd-agent-platform/core/dist/verification/task-evidence-judgment.js.map +1 -0
  240. package/node_modules/@sdd-agent-platform/core/dist/verification/test-runtime.js +21 -21
  241. package/node_modules/@sdd-agent-platform/core/dist/verification/test-runtime.js.map +1 -1
  242. package/node_modules/@sdd-agent-platform/core/dist/verification/validation-wave.d.ts +0 -18
  243. package/node_modules/@sdd-agent-platform/core/dist/verification/validation-wave.js +5 -27
  244. package/node_modules/@sdd-agent-platform/core/dist/verification/validation-wave.js.map +1 -1
  245. package/node_modules/@sdd-agent-platform/core/dist/verification/verify-contract.js +45 -45
  246. package/node_modules/@sdd-agent-platform/core/dist/verification/verify-contract.js.map +1 -1
  247. package/node_modules/@sdd-agent-platform/core/dist/verification.d.ts +3 -3
  248. package/node_modules/@sdd-agent-platform/core/dist/verification.js +2 -2
  249. package/node_modules/@sdd-agent-platform/core/dist/verification.js.map +1 -1
  250. package/node_modules/@sdd-agent-platform/core/dist/work-units/contracts.d.ts +1 -1
  251. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/evidence-packet.js +9 -227
  252. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/evidence-packet.js.map +1 -1
  253. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/hard-checks.js +9 -50
  254. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/hard-checks.js.map +1 -1
  255. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/policy.js +4 -42
  256. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/policy.js.map +1 -1
  257. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/types.d.ts +2 -3
  258. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/affected-file-conflicts.d.ts +1 -0
  259. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/affected-file-conflicts.js +2 -1
  260. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/affected-file-conflicts.js.map +1 -1
  261. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/dependencies.js +1 -1
  262. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/latest-eligible-run.d.ts +1 -0
  263. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/latest-eligible-run.js +23 -63
  264. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/latest-eligible-run.js.map +1 -1
  265. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/resolve.d.ts +2 -2
  266. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/resolve.js +43 -65
  267. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/resolve.js.map +1 -1
  268. package/node_modules/@sdd-agent-platform/core/package.json +5 -2
  269. package/node_modules/@sdd-agent-platform/core/src/ai-tools.test.ts +238 -185
  270. package/node_modules/@sdd-agent-platform/core/src/ai-tools.ts +56 -73
  271. package/node_modules/@sdd-agent-platform/core/src/artifacts/ingestion.test.ts +189 -227
  272. package/node_modules/@sdd-agent-platform/core/src/artifacts/ingestion.ts +222 -278
  273. package/node_modules/@sdd-agent-platform/core/src/artifacts/sdd-evidence.test.ts +28 -28
  274. package/node_modules/@sdd-agent-platform/core/src/artifacts/sdd-evidence.ts +301 -301
  275. package/node_modules/@sdd-agent-platform/core/src/artifacts/sdd-result.test.ts +181 -181
  276. package/node_modules/@sdd-agent-platform/core/src/artifacts/sdd-result.ts +231 -240
  277. package/node_modules/@sdd-agent-platform/core/src/artifacts/templates.ts +99 -99
  278. package/node_modules/@sdd-agent-platform/core/src/artifacts.ts +4 -4
  279. package/node_modules/@sdd-agent-platform/core/src/coding-facts/contracts.ts +79 -79
  280. package/node_modules/@sdd-agent-platform/core/src/coding-facts.ts +1 -1
  281. package/node_modules/@sdd-agent-platform/core/src/config/init-project.test.ts +314 -318
  282. package/node_modules/@sdd-agent-platform/core/src/config/init-project.ts +128 -123
  283. package/node_modules/@sdd-agent-platform/core/src/config/project-config.ts +265 -265
  284. package/node_modules/@sdd-agent-platform/core/src/config/project-detection.ts +147 -147
  285. package/node_modules/@sdd-agent-platform/core/src/config/starter-documents.ts +400 -432
  286. package/node_modules/@sdd-agent-platform/core/src/context/budget.ts +30 -30
  287. package/node_modules/@sdd-agent-platform/core/src/context/build-package.ts +304 -311
  288. package/node_modules/@sdd-agent-platform/core/src/context/command-summary.ts +45 -45
  289. package/node_modules/@sdd-agent-platform/core/src/context/context-build.test.ts +188 -189
  290. package/node_modules/@sdd-agent-platform/core/src/context/evidence-summary.ts +144 -163
  291. package/node_modules/@sdd-agent-platform/core/src/context/log-worker.ts +48 -48
  292. package/node_modules/@sdd-agent-platform/core/src/context/source-refs.ts +41 -41
  293. package/node_modules/@sdd-agent-platform/core/src/context-offload/contracts.ts +47 -47
  294. package/node_modules/@sdd-agent-platform/core/src/context-offload/runtime.test.ts +71 -71
  295. package/node_modules/@sdd-agent-platform/core/src/context-offload/runtime.ts +178 -178
  296. package/node_modules/@sdd-agent-platform/core/src/context-offload.ts +2 -2
  297. package/node_modules/@sdd-agent-platform/core/src/context.ts +6 -6
  298. package/node_modules/@sdd-agent-platform/core/src/contracts/issues.ts +13 -13
  299. package/node_modules/@sdd-agent-platform/core/src/contracts.test.ts +9 -9
  300. package/node_modules/@sdd-agent-platform/core/src/contracts.ts +121 -116
  301. package/node_modules/@sdd-agent-platform/core/src/delegation/delegation.test.ts +183 -183
  302. package/node_modules/@sdd-agent-platform/core/src/delegation/model.ts +23 -26
  303. package/node_modules/@sdd-agent-platform/core/src/delegation/queue.ts +58 -58
  304. package/node_modules/@sdd-agent-platform/core/src/delegation/run-state.ts +14 -14
  305. package/node_modules/@sdd-agent-platform/core/src/delegation/state-machine.ts +90 -90
  306. package/node_modules/@sdd-agent-platform/core/src/delegation/validation.ts +124 -127
  307. package/node_modules/@sdd-agent-platform/core/src/delegation.ts +26 -26
  308. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/ai-entries.ts +28 -28
  309. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/document-chain.ts +104 -112
  310. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/local-run-index.ts +19 -27
  311. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/project.ts +84 -84
  312. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/registries.ts +252 -251
  313. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/run-evidence.ts +330 -330
  314. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/run-records.ts +79 -79
  315. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/run-trust.ts +128 -107
  316. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/runtime-contracts.ts +300 -300
  317. package/node_modules/@sdd-agent-platform/core/src/doctor/doctor.test.ts +628 -755
  318. package/node_modules/@sdd-agent-platform/core/src/doctor/doctor.ts +301 -453
  319. package/node_modules/@sdd-agent-platform/core/src/doctor/model.ts +13 -13
  320. package/node_modules/@sdd-agent-platform/core/src/doctor/summary.ts +11 -11
  321. package/node_modules/@sdd-agent-platform/core/src/doctor.ts +2 -2
  322. package/node_modules/@sdd-agent-platform/core/src/evidence/lookup.ts +80 -88
  323. package/node_modules/@sdd-agent-platform/core/src/evidence-runtime/contracts.ts +48 -48
  324. package/node_modules/@sdd-agent-platform/core/src/evidence-runtime.ts +1 -1
  325. package/node_modules/@sdd-agent-platform/core/src/execution/agent-execution-records.ts +195 -195
  326. package/node_modules/@sdd-agent-platform/core/src/execution/background-executor.test.ts +187 -235
  327. package/node_modules/@sdd-agent-platform/core/src/execution/background-executor.ts +305 -305
  328. package/node_modules/@sdd-agent-platform/core/src/execution/foreground-subagents.test.ts +97 -106
  329. package/node_modules/@sdd-agent-platform/core/src/execution/foreground-subagents.ts +453 -453
  330. package/node_modules/@sdd-agent-platform/core/src/execution/host-invocation.ts +225 -226
  331. package/node_modules/@sdd-agent-platform/core/src/execution/resident-worker.test.ts +132 -143
  332. package/node_modules/@sdd-agent-platform/core/src/execution/resident-worker.ts +436 -437
  333. package/node_modules/@sdd-agent-platform/core/src/execution/stage-team-runtime.test.ts +102 -102
  334. package/node_modules/@sdd-agent-platform/core/src/execution/stage-team-runtime.ts +271 -271
  335. package/node_modules/@sdd-agent-platform/core/src/execution/wave-executor.test.ts +111 -121
  336. package/node_modules/@sdd-agent-platform/core/src/execution/wave-executor.ts +231 -231
  337. package/node_modules/@sdd-agent-platform/core/src/execution.ts +5 -5
  338. package/node_modules/@sdd-agent-platform/core/src/governance/policy.test.ts +57 -65
  339. package/node_modules/@sdd-agent-platform/core/src/governance/policy.ts +175 -175
  340. package/node_modules/@sdd-agent-platform/core/src/governance.ts +1 -1
  341. package/node_modules/@sdd-agent-platform/core/src/instructions.test.ts +80 -64
  342. package/node_modules/@sdd-agent-platform/core/src/instructions.ts +32 -68
  343. package/node_modules/@sdd-agent-platform/core/src/lifecycle/decision-gate.test.ts +174 -174
  344. package/node_modules/@sdd-agent-platform/core/src/lifecycle/decision-gate.ts +373 -373
  345. package/node_modules/@sdd-agent-platform/core/src/lifecycle/rendering.ts +29 -29
  346. package/node_modules/@sdd-agent-platform/core/src/lifecycle/risk-signals.ts +146 -146
  347. package/node_modules/@sdd-agent-platform/core/src/lifecycle/ship.test.ts +47 -47
  348. package/node_modules/@sdd-agent-platform/core/src/lifecycle/ship.ts +255 -280
  349. package/node_modules/@sdd-agent-platform/core/src/lifecycle-graph/contracts.ts +179 -0
  350. package/node_modules/@sdd-agent-platform/core/src/lifecycle-graph/kernel.ts +522 -0
  351. package/node_modules/@sdd-agent-platform/core/src/lifecycle-graph.ts +2 -0
  352. package/node_modules/@sdd-agent-platform/core/src/lifecycle.ts +4 -4
  353. package/node_modules/@sdd-agent-platform/core/src/orchestration/contracts.ts +50 -50
  354. package/node_modules/@sdd-agent-platform/core/src/orchestration/index.ts +2 -2
  355. package/node_modules/@sdd-agent-platform/core/src/orchestration/runtime.ts +331 -394
  356. package/node_modules/@sdd-agent-platform/core/src/path-safety.test.ts +22 -22
  357. package/node_modules/@sdd-agent-platform/core/src/phase8-contracts.test.ts +243 -242
  358. package/node_modules/@sdd-agent-platform/core/src/phase8-projection-compat.test.ts +152 -153
  359. package/node_modules/@sdd-agent-platform/core/src/phase8-risk-kernel.test.ts +277 -277
  360. package/node_modules/@sdd-agent-platform/core/src/phase9-lifecycle-graph.test.ts +103 -0
  361. package/node_modules/@sdd-agent-platform/core/src/planning/task-graph.test.ts +88 -88
  362. package/node_modules/@sdd-agent-platform/core/src/planning/task-graph.ts +222 -222
  363. package/node_modules/@sdd-agent-platform/core/src/planning/wave-plan.test.ts +79 -79
  364. package/node_modules/@sdd-agent-platform/core/src/planning/wave-plan.ts +160 -160
  365. package/node_modules/@sdd-agent-platform/core/src/planning.ts +2 -2
  366. package/node_modules/@sdd-agent-platform/core/src/registries/agent-capability-catalog.ts +426 -473
  367. package/node_modules/@sdd-agent-platform/core/src/registries/agent-registry.ts +230 -146
  368. package/node_modules/@sdd-agent-platform/core/src/registries/agent-runtime-static.ts +142 -142
  369. package/node_modules/@sdd-agent-platform/core/src/registries/capability-sources.ts +253 -253
  370. package/node_modules/@sdd-agent-platform/core/src/registries/command-team-runtime.ts +302 -309
  371. package/node_modules/@sdd-agent-platform/core/src/registries/eval-learning-context.ts +246 -246
  372. package/node_modules/@sdd-agent-platform/core/src/registries/plan-scout-domains.ts +89 -0
  373. package/node_modules/@sdd-agent-platform/core/src/registries/query-status.ts +119 -119
  374. package/node_modules/@sdd-agent-platform/core/src/registries/registries.test.ts +454 -445
  375. package/node_modules/@sdd-agent-platform/core/src/registries/skill-capabilities.ts +37 -37
  376. package/node_modules/@sdd-agent-platform/core/src/registries/tool-capabilities.ts +135 -135
  377. package/node_modules/@sdd-agent-platform/core/src/registries/tool-plugins.ts +132 -132
  378. package/node_modules/@sdd-agent-platform/core/src/registries/worker-adapters.ts +144 -144
  379. package/node_modules/@sdd-agent-platform/core/src/registries/workflow-gates.ts +111 -111
  380. package/node_modules/@sdd-agent-platform/core/src/registries.ts +42 -42
  381. package/node_modules/@sdd-agent-platform/core/src/risk/consumer-diagnostics.ts +98 -97
  382. package/node_modules/@sdd-agent-platform/core/src/risk/contracts.ts +63 -63
  383. package/node_modules/@sdd-agent-platform/core/src/risk/kernel.ts +233 -233
  384. package/node_modules/@sdd-agent-platform/core/src/risk/legacy-adapters.ts +251 -263
  385. package/node_modules/@sdd-agent-platform/core/src/risk/workflow-gates.ts +203 -205
  386. package/node_modules/@sdd-agent-platform/core/src/risk.ts +5 -5
  387. package/node_modules/@sdd-agent-platform/core/src/router/agent-runtime-config.ts +327 -327
  388. package/node_modules/@sdd-agent-platform/core/src/router/agent-runtime.ts +388 -390
  389. package/node_modules/@sdd-agent-platform/core/src/router/profile-resolution.ts +154 -154
  390. package/node_modules/@sdd-agent-platform/core/src/router/risk-policy.ts +33 -33
  391. package/node_modules/@sdd-agent-platform/core/src/router/route-cache.ts +100 -100
  392. package/node_modules/@sdd-agent-platform/core/src/router/route-projection.ts +356 -356
  393. package/node_modules/@sdd-agent-platform/core/src/router/route-sdd-task.test.ts +428 -665
  394. package/node_modules/@sdd-agent-platform/core/src/router/route-sdd-task.ts +2 -2
  395. package/node_modules/@sdd-agent-platform/core/src/router/routing-rules.ts +73 -73
  396. package/node_modules/@sdd-agent-platform/core/src/router/routing.ts +189 -223
  397. package/node_modules/@sdd-agent-platform/core/src/router/runtime-import.ts +464 -453
  398. package/node_modules/@sdd-agent-platform/core/src/router/runtime-inspection.ts +124 -124
  399. package/node_modules/@sdd-agent-platform/core/src/router/runtime-registry.ts +123 -123
  400. package/node_modules/@sdd-agent-platform/core/src/router/runtime-validation.ts +277 -277
  401. package/node_modules/@sdd-agent-platform/core/src/router/stage-route-binding.ts +273 -279
  402. package/node_modules/@sdd-agent-platform/core/src/router/team-mode.ts +170 -170
  403. package/node_modules/@sdd-agent-platform/core/src/router.ts +5 -6
  404. package/node_modules/@sdd-agent-platform/core/src/run-state/artifacts.ts +126 -240
  405. package/node_modules/@sdd-agent-platform/core/src/run-state/events.ts +27 -27
  406. package/node_modules/@sdd-agent-platform/core/src/run-state/inspect-run.ts +172 -172
  407. package/node_modules/@sdd-agent-platform/core/src/run-state/invocation-ledger.ts +109 -109
  408. package/node_modules/@sdd-agent-platform/core/src/run-state/model.ts +252 -253
  409. package/node_modules/@sdd-agent-platform/core/src/run-state/run-index.test.ts +80 -52
  410. package/node_modules/@sdd-agent-platform/core/src/run-state/run-index.ts +301 -352
  411. package/node_modules/@sdd-agent-platform/core/src/run-state/run-state.test.ts +70 -118
  412. package/node_modules/@sdd-agent-platform/core/src/run-state/run-state.ts +406 -416
  413. package/node_modules/@sdd-agent-platform/core/src/run-state/task-evidence.ts +198 -252
  414. package/node_modules/@sdd-agent-platform/core/src/run-state/timing.ts +146 -146
  415. package/node_modules/@sdd-agent-platform/core/src/run-state.ts +8 -9
  416. package/node_modules/@sdd-agent-platform/core/src/runtime-analysis/build.ts +60 -60
  417. package/node_modules/@sdd-agent-platform/core/src/runtime-analysis/findings.ts +249 -256
  418. package/node_modules/@sdd-agent-platform/core/src/runtime-analysis/model.ts +139 -140
  419. package/node_modules/@sdd-agent-platform/core/src/runtime-analysis.test.ts +65 -66
  420. package/node_modules/@sdd-agent-platform/core/src/runtime-analysis.ts +2 -2
  421. package/node_modules/@sdd-agent-platform/core/src/runtime-paths.ts +249 -253
  422. package/node_modules/@sdd-agent-platform/core/src/runtime-projection-p0.test.ts +101 -96
  423. package/node_modules/@sdd-agent-platform/core/src/runtime-projection-p0.ts +314 -292
  424. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/artifact-depth.test.ts +380 -0
  425. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/artifact-depth.ts +207 -0
  426. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/context.ts +111 -111
  427. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/document-hashes.ts +207 -306
  428. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/run-binding.ts +95 -97
  429. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/task-inspection.ts +39 -39
  430. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/task-parser.test.ts +467 -523
  431. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/task-parser.ts +738 -709
  432. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/task-rendering.ts +81 -81
  433. package/node_modules/@sdd-agent-platform/core/src/sdd-docs.ts +5 -5
  434. package/node_modules/@sdd-agent-platform/core/src/spec-manager-contracts.ts +13 -0
  435. package/node_modules/@sdd-agent-platform/core/src/stage-artifacts.ts +435 -450
  436. package/node_modules/@sdd-agent-platform/core/src/stage-collaboration-contracts.ts +316 -322
  437. package/node_modules/@sdd-agent-platform/core/src/stage-collaboration.test.ts +2963 -2902
  438. package/node_modules/@sdd-agent-platform/core/src/stage-collaboration.ts +5856 -5831
  439. package/node_modules/@sdd-agent-platform/core/src/stage-runtime/contracts.ts +40 -40
  440. package/node_modules/@sdd-agent-platform/core/src/stage-runtime/runtime.test.ts +209 -209
  441. package/node_modules/@sdd-agent-platform/core/src/stage-runtime/runtime.ts +360 -360
  442. package/node_modules/@sdd-agent-platform/core/src/stage-runtime.ts +2 -2
  443. package/node_modules/@sdd-agent-platform/core/src/status/project-status.test.ts +288 -511
  444. package/node_modules/@sdd-agent-platform/core/src/status/project-status.ts +651 -851
  445. package/node_modules/@sdd-agent-platform/core/src/status.ts +2 -2
  446. package/node_modules/@sdd-agent-platform/core/src/storage/json-io.ts +10 -10
  447. package/node_modules/@sdd-agent-platform/core/src/storage/runtime-store.test.ts +489 -681
  448. package/node_modules/@sdd-agent-platform/core/src/storage/runtime-store.ts +1981 -1981
  449. package/node_modules/@sdd-agent-platform/core/src/subagents/contracts.ts +45 -45
  450. package/node_modules/@sdd-agent-platform/core/src/subagents/runtime.test.ts +232 -232
  451. package/node_modules/@sdd-agent-platform/core/src/subagents/runtime.ts +307 -307
  452. package/node_modules/@sdd-agent-platform/core/src/subagents.ts +2 -2
  453. package/node_modules/@sdd-agent-platform/core/src/task-execution-contract.test.ts +141 -0
  454. package/node_modules/@sdd-agent-platform/core/src/task-execution-contract.ts +566 -0
  455. package/node_modules/@sdd-agent-platform/core/src/task-risk-profile.ts +193 -193
  456. package/node_modules/@sdd-agent-platform/core/src/test-support/fixtures.ts +413 -398
  457. package/node_modules/@sdd-agent-platform/core/src/test-support/run-state.ts +102 -56
  458. package/node_modules/@sdd-agent-platform/core/src/test-support.ts +2 -2
  459. package/node_modules/@sdd-agent-platform/core/src/truth-reconciliation.test.ts +72 -72
  460. package/node_modules/@sdd-agent-platform/core/src/truth-reconciliation.ts +9 -12
  461. package/node_modules/@sdd-agent-platform/core/src/verification/rendering.ts +137 -137
  462. package/node_modules/@sdd-agent-platform/core/src/verification/review-gate.test.ts +77 -84
  463. package/node_modules/@sdd-agent-platform/core/src/verification/review-gate.ts +77 -77
  464. package/node_modules/@sdd-agent-platform/core/src/verification/single-task-loop.ts +455 -506
  465. package/node_modules/@sdd-agent-platform/core/src/verification/{goal-verify.test.ts → task-evidence-judgment.test.ts} +261 -261
  466. package/node_modules/@sdd-agent-platform/core/src/verification/{goal-verify.ts → task-evidence-judgment.ts} +619 -619
  467. package/node_modules/@sdd-agent-platform/core/src/verification/test-runtime.ts +1190 -1190
  468. package/node_modules/@sdd-agent-platform/core/src/verification/validation-cache.ts +106 -106
  469. package/node_modules/@sdd-agent-platform/core/src/verification/validation-wave.ts +513 -556
  470. package/node_modules/@sdd-agent-platform/core/src/verification/verify-contract.ts +334 -334
  471. package/node_modules/@sdd-agent-platform/core/src/verification.ts +8 -8
  472. package/node_modules/@sdd-agent-platform/core/src/work-units/contracts.ts +26 -26
  473. package/node_modules/@sdd-agent-platform/core/src/work-units/runtime.test.ts +88 -88
  474. package/node_modules/@sdd-agent-platform/core/src/work-units/runtime.ts +112 -112
  475. package/node_modules/@sdd-agent-platform/core/src/work-units.ts +2 -2
  476. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/evidence-packet.ts +190 -425
  477. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/hard-checks.test.ts +169 -507
  478. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/hard-checks.ts +136 -182
  479. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/policy.test.ts +135 -174
  480. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/policy.ts +153 -194
  481. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/types.ts +111 -115
  482. package/node_modules/@sdd-agent-platform/core/src/workflow-state/affected-file-conflicts.ts +95 -93
  483. package/node_modules/@sdd-agent-platform/core/src/workflow-state/dependencies.test.ts +32 -32
  484. package/node_modules/@sdd-agent-platform/core/src/workflow-state/dependencies.ts +114 -114
  485. package/node_modules/@sdd-agent-platform/core/src/workflow-state/latest-eligible-run.ts +184 -224
  486. package/node_modules/@sdd-agent-platform/core/src/workflow-state/migration-recovery.ts +158 -158
  487. package/node_modules/@sdd-agent-platform/core/src/workflow-state/repair-contract.ts +77 -77
  488. package/node_modules/@sdd-agent-platform/core/src/workflow-state/resolve-task-run.ts +114 -114
  489. package/node_modules/@sdd-agent-platform/core/src/workflow-state/resolve.test.ts +969 -956
  490. package/node_modules/@sdd-agent-platform/core/src/workflow-state/resolve.ts +967 -992
  491. package/node_modules/@sdd-agent-platform/core/src/workflow-state/runtime-projections.ts +712 -712
  492. package/node_modules/@sdd-agent-platform/core/src/workflow-state.ts +2 -2
  493. package/node_modules/@sdd-agent-platform/core/src/worktree/isolation.ts +130 -130
  494. package/node_modules/@sdd-agent-platform/core/src/worktree/lifecycle.ts +269 -269
  495. package/node_modules/@sdd-agent-platform/core/src/worktree/worktree.test.ts +150 -150
  496. package/node_modules/@sdd-agent-platform/core/src/worktree.ts +2 -2
  497. package/node_modules/@sdd-agent-platform/core/tsconfig.json +15 -15
  498. package/package.json +2 -2
  499. package/packages/cli/dist/args.js +2 -2
  500. package/packages/cli/dist/args.js.map +1 -1
  501. package/packages/cli/dist/commands/ai-tools.js +2 -13
  502. package/packages/cli/dist/commands/ai-tools.js.map +1 -1
  503. package/packages/cli/dist/commands/{verifies.d.ts → artifact.d.ts} +1 -1
  504. package/packages/cli/dist/commands/artifact.js +168 -0
  505. package/packages/cli/dist/commands/artifact.js.map +1 -0
  506. package/packages/cli/dist/commands/context.js +1 -1
  507. package/packages/cli/dist/commands/context.js.map +1 -1
  508. package/packages/cli/dist/commands/evidence.js.map +1 -0
  509. package/packages/cli/dist/commands/execution.js +127 -49
  510. package/packages/cli/dist/commands/execution.js.map +1 -1
  511. package/packages/cli/dist/commands/governance.js +1 -1
  512. package/packages/cli/dist/commands/governance.js.map +1 -1
  513. package/packages/cli/dist/commands/init.js +1 -6
  514. package/packages/cli/dist/commands/init.js.map +1 -1
  515. package/packages/cli/dist/commands/instructions.d.ts +1 -1
  516. package/packages/cli/dist/commands/instructions.js +15 -1
  517. package/packages/cli/dist/commands/instructions.js.map +1 -1
  518. package/packages/cli/dist/commands/registry/runtime.js +63 -40
  519. package/packages/cli/dist/commands/registry/runtime.js.map +1 -1
  520. package/packages/cli/dist/commands/run.js +13 -52
  521. package/packages/cli/dist/commands/run.js.map +1 -1
  522. package/packages/cli/dist/commands/stage-close.d.ts +60 -0
  523. package/packages/cli/dist/commands/stage-close.js +270 -41
  524. package/packages/cli/dist/commands/stage-close.js.map +1 -1
  525. package/packages/cli/dist/commands/status.js +9 -68
  526. package/packages/cli/dist/commands/status.js.map +1 -1
  527. package/packages/cli/dist/commands/tasks.js.map +1 -1
  528. package/packages/cli/dist/dispatch.js +6 -26
  529. package/packages/cli/dist/dispatch.js.map +1 -1
  530. package/packages/cli/dist/help.js +153 -159
  531. package/packages/cli/dist/help.js.map +1 -1
  532. package/packages/cli/dist/renderers/artifacts.d.ts +5 -0
  533. package/packages/cli/dist/renderers/artifacts.js +43 -0
  534. package/packages/cli/dist/renderers/artifacts.js.map +1 -0
  535. package/packages/cli/dist/renderers/doctor.js +1 -2
  536. package/packages/cli/dist/renderers/doctor.js.map +1 -1
  537. package/packages/cli/dist/renderers/execution.js +1 -1
  538. package/packages/cli/dist/renderers/execution.js.map +1 -1
  539. package/packages/cli/dist/renderers/json.d.ts +0 -1
  540. package/packages/cli/dist/renderers/json.js +0 -3
  541. package/packages/cli/dist/renderers/json.js.map +1 -1
  542. package/packages/cli/dist/renderers/registry-runtime.d.ts +1 -2
  543. package/packages/cli/dist/renderers/registry-runtime.js +0 -20
  544. package/packages/cli/dist/renderers/registry-runtime.js.map +1 -1
  545. package/packages/cli/dist/renderers/router.js +1 -1
  546. package/packages/cli/dist/renderers/router.js.map +1 -1
  547. package/packages/cli/dist/renderers/workflow.d.ts +53 -0
  548. package/packages/cli/dist/renderers/workflow.js +93 -34
  549. package/packages/cli/dist/renderers/workflow.js.map +1 -1
  550. package/packages/cli/dist/tsconfig.tsbuildinfo +1 -1
  551. package/packages/cli/package.json +2 -2
  552. package/packages/core/dist/ai-tools.js +56 -73
  553. package/packages/core/dist/ai-tools.js.map +1 -1
  554. package/packages/core/dist/artifacts/ingestion.js +9 -64
  555. package/packages/core/dist/artifacts/ingestion.js.map +1 -1
  556. package/packages/core/dist/artifacts/sdd-evidence.js +1 -1
  557. package/packages/core/dist/artifacts/sdd-evidence.js.map +1 -1
  558. package/packages/core/dist/artifacts/sdd-result.js +17 -26
  559. package/packages/core/dist/artifacts/sdd-result.js.map +1 -1
  560. package/packages/core/dist/config/init-project.d.ts +8 -7
  561. package/packages/core/dist/config/init-project.js +8 -12
  562. package/packages/core/dist/config/init-project.js.map +1 -1
  563. package/packages/core/dist/config/project-config.d.ts +1 -1
  564. package/packages/core/dist/config/project-config.js +1 -1
  565. package/packages/core/dist/config/project-config.js.map +1 -1
  566. package/packages/core/dist/config/starter-documents.d.ts +3 -4
  567. package/packages/core/dist/config/starter-documents.js +377 -411
  568. package/packages/core/dist/config/starter-documents.js.map +1 -1
  569. package/packages/core/dist/context/build-package.d.ts +1 -1
  570. package/packages/core/dist/context/build-package.js +18 -25
  571. package/packages/core/dist/context/build-package.js.map +1 -1
  572. package/packages/core/dist/context/evidence-summary.js +8 -26
  573. package/packages/core/dist/context/evidence-summary.js.map +1 -1
  574. package/packages/core/dist/context/log-worker.js +2 -2
  575. package/packages/core/dist/context/log-worker.js.map +1 -1
  576. package/packages/core/dist/context-offload/contracts.d.ts +1 -1
  577. package/packages/core/dist/contracts.d.ts +6 -1
  578. package/packages/core/dist/contracts.js +5 -0
  579. package/packages/core/dist/contracts.js.map +1 -1
  580. package/packages/core/dist/delegation/model.d.ts +0 -3
  581. package/packages/core/dist/delegation/validation.d.ts +0 -3
  582. package/packages/core/dist/delegation/validation.js +4 -7
  583. package/packages/core/dist/delegation/validation.js.map +1 -1
  584. package/packages/core/dist/doctor/checks/document-chain.js +3 -13
  585. package/packages/core/dist/doctor/checks/document-chain.js.map +1 -1
  586. package/packages/core/dist/doctor/checks/local-run-index.js +1 -9
  587. package/packages/core/dist/doctor/checks/local-run-index.js.map +1 -1
  588. package/packages/core/dist/doctor/checks/project.js +9 -9
  589. package/packages/core/dist/doctor/checks/project.js.map +1 -1
  590. package/packages/core/dist/doctor/checks/registries.js +1 -0
  591. package/packages/core/dist/doctor/checks/registries.js.map +1 -1
  592. package/packages/core/dist/doctor/checks/run-evidence.js +4 -4
  593. package/packages/core/dist/doctor/checks/run-evidence.js.map +1 -1
  594. package/packages/core/dist/doctor/checks/run-trust.js +24 -0
  595. package/packages/core/dist/doctor/checks/run-trust.js.map +1 -1
  596. package/packages/core/dist/doctor/checks/runtime-contracts.js +2 -2
  597. package/packages/core/dist/doctor/checks/runtime-contracts.js.map +1 -1
  598. package/packages/core/dist/doctor/doctor.js +43 -180
  599. package/packages/core/dist/doctor/doctor.js.map +1 -1
  600. package/packages/core/dist/evidence/lookup.d.ts +1 -1
  601. package/packages/core/dist/evidence/lookup.js +7 -14
  602. package/packages/core/dist/evidence/lookup.js.map +1 -1
  603. package/packages/core/dist/evidence-runtime/coordination.js +110 -0
  604. package/packages/core/dist/evidence-runtime/coordination.js.map +1 -0
  605. package/packages/core/dist/execution/background-executor.js +4 -4
  606. package/packages/core/dist/execution/background-executor.js.map +1 -1
  607. package/packages/core/dist/execution/foreground-subagents.js +3 -3
  608. package/packages/core/dist/execution/foreground-subagents.js.map +1 -1
  609. package/packages/core/dist/execution/host-invocation.js +85 -86
  610. package/packages/core/dist/execution/host-invocation.js.map +1 -1
  611. package/packages/core/dist/execution/resident-worker.js +2 -3
  612. package/packages/core/dist/execution/resident-worker.js.map +1 -1
  613. package/packages/core/dist/execution/stage-team-runtime.js +2 -2
  614. package/packages/core/dist/execution/stage-team-runtime.js.map +1 -1
  615. package/packages/core/dist/governance/policy.d.ts +1 -1
  616. package/packages/core/dist/governance/policy.js +1 -1
  617. package/packages/core/dist/governance/policy.js.map +1 -1
  618. package/packages/core/dist/instructions.d.ts +1 -1
  619. package/packages/core/dist/instructions.js +31 -67
  620. package/packages/core/dist/instructions.js.map +1 -1
  621. package/packages/core/dist/lifecycle/decision-gate.js +1 -1
  622. package/packages/core/dist/lifecycle/decision-gate.js.map +1 -1
  623. package/packages/core/dist/lifecycle/ship.d.ts +0 -1
  624. package/packages/core/dist/lifecycle/ship.js +59 -85
  625. package/packages/core/dist/lifecycle/ship.js.map +1 -1
  626. package/packages/core/dist/lifecycle-graph/contracts.d.ts +159 -0
  627. package/packages/core/dist/lifecycle-graph/contracts.js +7 -0
  628. package/packages/core/dist/lifecycle-graph/contracts.js.map +1 -0
  629. package/packages/core/dist/lifecycle-graph/kernel.d.ts +16 -0
  630. package/packages/core/dist/lifecycle-graph/kernel.js +461 -0
  631. package/packages/core/dist/lifecycle-graph/kernel.js.map +1 -0
  632. package/packages/core/dist/lifecycle-graph.d.ts +2 -0
  633. package/packages/core/dist/lifecycle-graph.js +3 -0
  634. package/packages/core/dist/lifecycle-graph.js.map +1 -0
  635. package/packages/core/dist/orchestration/contracts.d.ts +1 -1
  636. package/packages/core/dist/orchestration/runtime.d.ts +2 -12
  637. package/packages/core/dist/orchestration/runtime.js +32 -80
  638. package/packages/core/dist/orchestration/runtime.js.map +1 -1
  639. package/packages/core/dist/registries/agent-capability-catalog.d.ts +2 -5
  640. package/packages/core/dist/registries/agent-capability-catalog.js +27 -69
  641. package/packages/core/dist/registries/agent-capability-catalog.js.map +1 -1
  642. package/packages/core/dist/registries/agent-registry.js +118 -34
  643. package/packages/core/dist/registries/agent-registry.js.map +1 -1
  644. package/packages/core/dist/registries/agent-runtime-static.js +1 -1
  645. package/packages/core/dist/registries/agent-runtime-static.js.map +1 -1
  646. package/packages/core/dist/registries/capability-sources.js +1 -1
  647. package/packages/core/dist/registries/command-team-runtime.d.ts +1 -1
  648. package/packages/core/dist/registries/command-team-runtime.js +8 -15
  649. package/packages/core/dist/registries/command-team-runtime.js.map +1 -1
  650. package/packages/core/dist/registries/eval-learning-context.js +4 -4
  651. package/packages/core/dist/registries/eval-learning-context.js.map +1 -1
  652. package/packages/core/dist/registries/plan-scout-domains.d.ts +13 -0
  653. package/packages/core/dist/registries/plan-scout-domains.js +76 -0
  654. package/packages/core/dist/registries/plan-scout-domains.js.map +1 -0
  655. package/packages/core/dist/registries/query-status.js +2 -2
  656. package/packages/core/dist/registries/query-status.js.map +1 -1
  657. package/packages/core/dist/registries/skill-capabilities.js +7 -7
  658. package/packages/core/dist/registries/skill-capabilities.js.map +1 -1
  659. package/packages/core/dist/registries/tool-capabilities.js +4 -4
  660. package/packages/core/dist/registries/tool-capabilities.js.map +1 -1
  661. package/packages/core/dist/registries/tool-plugins.js +2 -2
  662. package/packages/core/dist/registries/tool-plugins.js.map +1 -1
  663. package/packages/core/dist/registries/worker-adapters.js +11 -11
  664. package/packages/core/dist/registries/worker-adapters.js.map +1 -1
  665. package/packages/core/dist/registries/workflow-gates.d.ts +1 -1
  666. package/packages/core/dist/registries/workflow-gates.js +21 -21
  667. package/packages/core/dist/registries/workflow-gates.js.map +1 -1
  668. package/packages/core/dist/risk/consumer-diagnostics.js +2 -1
  669. package/packages/core/dist/risk/consumer-diagnostics.js.map +1 -1
  670. package/packages/core/dist/risk/kernel.js +6 -6
  671. package/packages/core/dist/risk/kernel.js.map +1 -1
  672. package/packages/core/dist/risk/legacy-adapters.js +11 -23
  673. package/packages/core/dist/risk/legacy-adapters.js.map +1 -1
  674. package/packages/core/dist/risk/workflow-gates.d.ts +2 -2
  675. package/packages/core/dist/risk/workflow-gates.js +18 -20
  676. package/packages/core/dist/risk/workflow-gates.js.map +1 -1
  677. package/packages/core/dist/router/agent-runtime.d.ts +0 -2
  678. package/packages/core/dist/router/route-projection.js +1 -1
  679. package/packages/core/dist/router/route-projection.js.map +1 -1
  680. package/packages/core/dist/router/routing.js +16 -48
  681. package/packages/core/dist/router/routing.js.map +1 -1
  682. package/packages/core/dist/router/runtime-import.js +11 -1
  683. package/packages/core/dist/router/runtime-import.js.map +1 -1
  684. package/packages/core/dist/router/runtime-validation.js +2 -2
  685. package/packages/core/dist/router/runtime-validation.js.map +1 -1
  686. package/packages/core/dist/router/stage-route-binding.d.ts +2 -2
  687. package/packages/core/dist/router/stage-route-binding.js +20 -28
  688. package/packages/core/dist/router/stage-route-binding.js.map +1 -1
  689. package/packages/core/dist/router.d.ts +0 -1
  690. package/packages/core/dist/router.js +0 -1
  691. package/packages/core/dist/router.js.map +1 -1
  692. package/packages/core/dist/run-state/artifacts.d.ts +6 -6
  693. package/packages/core/dist/run-state/artifacts.js +13 -124
  694. package/packages/core/dist/run-state/artifacts.js.map +1 -1
  695. package/packages/core/dist/run-state/inspect-run.d.ts +2 -0
  696. package/packages/core/dist/run-state/inspect-run.js +5 -7
  697. package/packages/core/dist/run-state/inspect-run.js.map +1 -1
  698. package/packages/core/dist/run-state/model.d.ts +28 -28
  699. package/packages/core/dist/run-state/run-index.d.ts +3 -2
  700. package/packages/core/dist/run-state/run-index.js +15 -66
  701. package/packages/core/dist/run-state/run-index.js.map +1 -1
  702. package/packages/core/dist/run-state/run-state.js +26 -36
  703. package/packages/core/dist/run-state/run-state.js.map +1 -1
  704. package/packages/core/dist/run-state/task-evidence.d.ts +0 -4
  705. package/packages/core/dist/run-state/task-evidence.js +5 -51
  706. package/packages/core/dist/run-state/task-evidence.js.map +1 -1
  707. package/packages/core/dist/run-state.d.ts +0 -1
  708. package/packages/core/dist/run-state.js +0 -1
  709. package/packages/core/dist/run-state.js.map +1 -1
  710. package/packages/core/dist/runtime-analysis/build.js +1 -1
  711. package/packages/core/dist/runtime-analysis/build.js.map +1 -1
  712. package/packages/core/dist/runtime-analysis/findings.js +7 -16
  713. package/packages/core/dist/runtime-analysis/findings.js.map +1 -1
  714. package/packages/core/dist/runtime-analysis/model.d.ts +1 -2
  715. package/packages/core/dist/runtime-paths.d.ts +0 -1
  716. package/packages/core/dist/runtime-paths.js +1 -4
  717. package/packages/core/dist/runtime-paths.js.map +1 -1
  718. package/packages/core/dist/runtime-projection-p0.d.ts +2 -2
  719. package/packages/core/dist/runtime-projection-p0.js +11 -0
  720. package/packages/core/dist/runtime-projection-p0.js.map +1 -1
  721. package/packages/core/dist/sdd-docs/artifact-depth.d.ts +14 -0
  722. package/packages/core/dist/sdd-docs/artifact-depth.js +179 -0
  723. package/packages/core/dist/sdd-docs/artifact-depth.js.map +1 -0
  724. package/packages/core/dist/sdd-docs/document-hashes.d.ts +0 -2
  725. package/packages/core/dist/sdd-docs/document-hashes.js +10 -97
  726. package/packages/core/dist/sdd-docs/document-hashes.js.map +1 -1
  727. package/packages/core/dist/sdd-docs/run-binding.d.ts +1 -1
  728. package/packages/core/dist/sdd-docs/run-binding.js +6 -8
  729. package/packages/core/dist/sdd-docs/run-binding.js.map +1 -1
  730. package/packages/core/dist/sdd-docs/task-parser.d.ts +5 -2
  731. package/packages/core/dist/sdd-docs/task-parser.js +85 -68
  732. package/packages/core/dist/sdd-docs/task-parser.js.map +1 -1
  733. package/packages/core/dist/sdd-docs/task-rendering.js +2 -2
  734. package/packages/core/dist/sdd-docs/task-rendering.js.map +1 -1
  735. package/packages/core/dist/spec-entry.js +40 -0
  736. package/packages/core/dist/spec-entry.js.map +1 -0
  737. package/packages/core/dist/spec-manager-contracts.d.ts +12 -0
  738. package/packages/core/dist/spec-manager-contracts.js +2 -0
  739. package/packages/core/dist/spec-manager-contracts.js.map +1 -0
  740. package/packages/core/dist/stage-artifacts.d.ts +2 -2
  741. package/packages/core/dist/stage-artifacts.js +19 -26
  742. package/packages/core/dist/stage-artifacts.js.map +1 -1
  743. package/packages/core/dist/stage-collaboration-contracts.d.ts +1 -1
  744. package/packages/core/dist/stage-collaboration-contracts.js +3 -6
  745. package/packages/core/dist/stage-collaboration-contracts.js.map +1 -1
  746. package/packages/core/dist/stage-collaboration.d.ts +111 -263
  747. package/packages/core/dist/stage-collaboration.js +1272 -1124
  748. package/packages/core/dist/stage-collaboration.js.map +1 -1
  749. package/packages/core/dist/stage-runtime/runtime.js +5 -5
  750. package/packages/core/dist/stage-runtime/runtime.js.map +1 -1
  751. package/packages/core/dist/status/project-status.d.ts +1 -44
  752. package/packages/core/dist/status/project-status.js +47 -170
  753. package/packages/core/dist/status/project-status.js.map +1 -1
  754. package/packages/core/dist/storage/runtime-store.js +73 -73
  755. package/packages/core/dist/subagents/contracts.d.ts +1 -1
  756. package/packages/core/dist/subagents/runtime.js +7 -7
  757. package/packages/core/dist/subagents/runtime.js.map +1 -1
  758. package/packages/core/dist/sync-back/apply.d.ts +1 -0
  759. package/packages/core/dist/sync-back/apply.js +2 -0
  760. package/packages/core/dist/sync-back/apply.js.map +1 -0
  761. package/packages/core/dist/sync-back/inspect.d.ts +1 -0
  762. package/packages/core/dist/sync-back/inspect.js +2 -0
  763. package/packages/core/dist/sync-back/inspect.js.map +1 -0
  764. package/packages/core/dist/sync-back.d.ts +1 -0
  765. package/packages/core/dist/sync-back.js +2 -0
  766. package/packages/core/dist/sync-back.js.map +1 -0
  767. package/packages/core/dist/task-execution-contract.d.ts +167 -0
  768. package/packages/core/dist/task-execution-contract.js +377 -0
  769. package/packages/core/dist/task-execution-contract.js.map +1 -0
  770. package/packages/core/dist/test-support/fixtures.js +329 -314
  771. package/packages/core/dist/test-support/fixtures.js.map +1 -1
  772. package/packages/core/dist/test-support/run-state.d.ts +1 -0
  773. package/packages/core/dist/test-support/run-state.js +53 -7
  774. package/packages/core/dist/test-support/run-state.js.map +1 -1
  775. package/packages/core/dist/truth-reconciliation.js +9 -12
  776. package/packages/core/dist/truth-reconciliation.js.map +1 -1
  777. package/packages/core/dist/tsconfig.tsbuildinfo +1 -1
  778. package/packages/core/dist/verification/goal-verify.d.ts +0 -48
  779. package/packages/core/dist/verification/goal-verify.js +1 -520
  780. package/packages/core/dist/verification/goal-verify.js.map +1 -1
  781. package/packages/core/dist/verification/rendering.d.ts +5 -5
  782. package/packages/core/dist/verification/rendering.js +14 -14
  783. package/packages/core/dist/verification/rendering.js.map +1 -1
  784. package/packages/core/dist/verification/single-task-loop.d.ts +1 -0
  785. package/packages/core/dist/verification/single-task-loop.js +111 -159
  786. package/packages/core/dist/verification/single-task-loop.js.map +1 -1
  787. package/packages/core/dist/verification/task-evidence-judgment.d.ts +49 -0
  788. package/packages/core/dist/verification/task-evidence-judgment.js +521 -0
  789. package/packages/core/dist/verification/task-evidence-judgment.js.map +1 -0
  790. package/packages/core/dist/verification/test-runtime.js +21 -21
  791. package/packages/core/dist/verification/test-runtime.js.map +1 -1
  792. package/packages/core/dist/verification/validation-wave.d.ts +0 -18
  793. package/packages/core/dist/verification/validation-wave.js +5 -27
  794. package/packages/core/dist/verification/validation-wave.js.map +1 -1
  795. package/packages/core/dist/verification/verify-contract.js +45 -45
  796. package/packages/core/dist/verification/verify-contract.js.map +1 -1
  797. package/packages/core/dist/verification.d.ts +3 -3
  798. package/packages/core/dist/verification.js +2 -2
  799. package/packages/core/dist/verification.js.map +1 -1
  800. package/packages/core/dist/work-units/contracts.d.ts +1 -1
  801. package/packages/core/dist/workflow-gate/evidence-packet.js +9 -227
  802. package/packages/core/dist/workflow-gate/evidence-packet.js.map +1 -1
  803. package/packages/core/dist/workflow-gate/hard-checks.js +9 -50
  804. package/packages/core/dist/workflow-gate/hard-checks.js.map +1 -1
  805. package/packages/core/dist/workflow-gate/policy.js +4 -42
  806. package/packages/core/dist/workflow-gate/policy.js.map +1 -1
  807. package/packages/core/dist/workflow-gate/types.d.ts +2 -3
  808. package/packages/core/dist/workflow-state/affected-file-conflicts.d.ts +1 -0
  809. package/packages/core/dist/workflow-state/affected-file-conflicts.js +2 -1
  810. package/packages/core/dist/workflow-state/affected-file-conflicts.js.map +1 -1
  811. package/packages/core/dist/workflow-state/dependencies.js +1 -1
  812. package/packages/core/dist/workflow-state/latest-eligible-run.d.ts +1 -0
  813. package/packages/core/dist/workflow-state/latest-eligible-run.js +23 -63
  814. package/packages/core/dist/workflow-state/latest-eligible-run.js.map +1 -1
  815. package/packages/core/dist/workflow-state/resolve.d.ts +2 -2
  816. package/packages/core/dist/workflow-state/resolve.js +43 -65
  817. package/packages/core/dist/workflow-state/resolve.js.map +1 -1
  818. package/packages/core/package.json +5 -2
  819. package/tsconfig.build.json +6 -7
  820. package/node_modules/@sdd-agent-platform/core/src/verification/single-task-loop.test.ts +0 -269
  821. package/node_modules/@sdd-agent-platform/core/src/verification/test-runtime.test.ts +0 -492
  822. package/node_modules/@sdd-agent-platform/core/src/verification/validation-wave.test.ts +0 -383
  823. package/node_modules/@sdd-agent-platform/core/src/verification/verify-contract.test.ts +0 -188
  824. package/packages/cli/dist/commands/lifecycle.d.ts +0 -6
  825. package/packages/cli/dist/commands/lifecycle.js +0 -125
  826. package/packages/cli/dist/commands/lifecycle.js.map +0 -1
  827. package/packages/cli/dist/commands/test.d.ts +0 -6
  828. package/packages/cli/dist/commands/test.js +0 -373
  829. package/packages/cli/dist/commands/test.js.map +0 -1
  830. package/packages/cli/dist/commands/verifies.js +0 -87
  831. package/packages/cli/dist/commands/verifies.js.map +0 -1
  832. package/packages/cli/dist/commands/verify.d.ts +0 -6
  833. package/packages/cli/dist/commands/verify.js +0 -330
  834. package/packages/cli/dist/commands/verify.js.map +0 -1
@@ -1,957 +1,970 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
4
- import { tmpdir } from 'node:os';
5
- import path from 'node:path';
6
- import { execFile } from 'node:child_process';
7
- import { promisify } from 'node:util';
8
-
9
- import { initProject } from '../config/init-project.js';
10
- import { createRun, readRunState, writeRunState } from '../run-state/run-state.js';
11
- import { hashTestDocument, validTaskMarkdown, writeBranchDocs } from '../test-support/fixtures.js';
12
- import { bindTestRunState, markTestRunReadyForShip } from '../test-support/run-state.js';
13
- import { createDelegationRecord } from '../delegation/validation.js';
14
- import { recordRuntimeProjectionEnvelope, recordRuntimeRepair } from '../storage/runtime-store.js';
15
- import { buildOpenRepairRecord } from './repair-contract.js';
16
- import { recordTruthAlignmentProjection, SPEC_COLLABORATION_ADJUDICATION_PROJECTION_TYPE, specCollaborationScopeKey, TEST_COLLABORATION_ADJUDICATION_PROJECTION_TYPE, testCollaborationScopeKey, type TruthAlignmentProjection } from '../stage-collaboration.js';
17
- import { readTruthReconciliationProjection } from '../truth-reconciliation.js';
18
- import { resolveWorkflowState } from './resolve.js';
19
- import { readNextIntentProjection, readTaskOrchestrationProjection, readValidationUnitProjection, readWorkflowCurrentStateProjection } from './runtime-projections.js';
20
-
21
- const execFileAsync = promisify(execFile);
22
-
23
- test('workflow state resolver projects branch docs latest run and next action', async () => {
24
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-'));
25
- try {
26
- await initProject(root);
27
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
28
- const run = await createRun(root, { runId: 'run-1' });
29
- await bindTestRunState(root, run.runId, 'feature', 'T1');
30
- await markTestRunReadyForShip(root, run.runId, 'T1');
31
-
32
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
33
-
34
- assert.equal(workflow.contract, 'phase-7.3-workflow-state-resolver-v1');
35
- assert.equal(workflow.workflowStatus, 'active');
36
- assert.equal(workflow.latestRun?.runId, 'run-1');
37
- assert.deepEqual(workflow.latestRunsByTask.map((entry) => `${entry.partition}:${entry.taskId}:${entry.runId}`), ['feature:T1:run-1']);
38
- assert.equal(workflow.taskCounts.total, 1);
39
- assert.equal(workflow.recommendedNextCommand, 'sdd ship close --branch feature --compact-json');
40
- assert.equal(workflow.nextIntent.bundle, 'ship');
41
- assert.equal(workflow.nextIntent.targetRuntimeStage, 'ship');
42
- assert.equal(workflow.nextIntent.hostProjections.find((projection) => projection.host === 'claude_code')?.entry, '/sdd:ship close --branch feature --compact-json');
43
- const currentStateProjection = await readWorkflowCurrentStateProjection(root, 'feature');
44
- const nextIntentProjection = await readNextIntentProjection(root, 'feature');
45
- const taskOrchestrationProjection = await readTaskOrchestrationProjection(root, 'feature');
46
- const validationUnitProjection = await readValidationUnitProjection(root, 'feature');
47
-
48
- assert.equal(currentStateProjection?.payload.contract, 'sdd-workflow-current-state-projection-v1');
49
- assert.equal(currentStateProjection?.payload.lifecycle.currentStage, 'ship');
50
- assert.equal(currentStateProjection?.payload.lifecycle.writer, 'runtime_sqlite');
51
- assert.equal(currentStateProjection?.payload.tasks[0]?.taskId, 'T1');
52
- assert.equal(currentStateProjection?.payload.tasks[0]?.consumability, 'consumable');
53
- assert.equal(currentStateProjection?.payload.validationUnits[0]?.validationUnitId, 'T1');
54
- assert.equal(taskOrchestrationProjection?.payload.contract, 'sdd-task-orchestration-projection-v1');
55
- assert.equal(taskOrchestrationProjection?.payload.tasks[0]?.taskId, 'T1');
56
- assert.equal(taskOrchestrationProjection?.payload.tasks[0]?.sourceRef.ref, 'specs/feature/tasks.md#T1');
57
- assert.equal(validationUnitProjection?.payload.contract, 'sdd-validation-unit-projection-v1');
58
- assert.deepEqual(validationUnitProjection?.payload.validationUnits[0]?.taskIds, ['T1']);
59
- assert.equal(nextIntentProjection?.payload.contract, 'sdd-next-intent-projection-v1');
60
- assert.equal(nextIntentProjection?.payload.advisory, true);
61
- assert.equal(nextIntentProjection?.payload.rules.recommendationIsNotAGate, true);
62
- assert.equal(nextIntentProjection?.payload.primary.canonicalCommand, workflow.nextIntent.canonicalCommand);
63
- assert.equal(nextIntentProjection?.payload.primary.targetRuntimeStage, 'ship');
64
- } finally {
65
- await rm(root, { recursive: true, force: true });
66
- }
67
- });
68
-
69
- test('workflow state routes validation PASS to goal-verify before ship readiness', async () => {
70
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-test-pass-'));
71
- try {
72
- await initProject(root);
73
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
74
- const run = await createRun(root, { runId: 'run-pass-no-syncback' });
75
- await bindTestRunState(root, run.runId, 'feature', 'T1');
76
- const bound = await readRunState(root, run.runId);
77
- await writeRunState(root, {
78
- ...bound,
79
- status: 'completed',
80
- validation: {
81
- status: 'pass',
82
- commands: ['npm test'],
83
- evidence: ['artifacts/validation-T1.md']
84
- }
85
- });
86
-
87
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
88
-
89
- assert.equal(workflow.nextIntent.stage, 'test');
90
- assert.equal(workflow.nextIntent.bundle, 'test');
91
- assert.equal(workflow.nextIntent.targetRuntimeStage, 'goal-verify');
92
- assert.equal(workflow.nextIntent.intent, 'run_goal_verify');
93
- assert.equal(workflow.recommendedNextCommand, 'sdd test close --branch feature --target goal-verify --compact-json');
94
- } finally {
95
- await rm(root, { recursive: true, force: true });
96
- }
97
- });
98
-
99
- test('workflow state routes non-aligned truthAlignment to owner stage-manager reconciliation', async () => {
100
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-truth-reconcile-'));
101
- try {
102
- await initProject(root);
103
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
104
- await recordTruthAlignmentProjection(root, truthAlignmentProjection({
105
- branch: 'feature',
106
- status: 'drift_detected',
107
- ownerStage: 'do',
108
- semanticImpact: 'material',
109
- invalidatesStages: ['do'],
110
- staleRefs: [{ kind: 'artifact', ref: '.sdd/runs/feature/do/implementation-v1.md', hash: 'old-implementation-hash' }],
111
- reasons: ['accepted implementation evidence no longer matches declared truth']
112
- }));
113
-
114
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
115
- const projection = await readTruthReconciliationProjection(root, 'feature');
116
-
117
- assert.equal(workflow.nextIntent.intent, 'reconcile_truth');
118
- assert.equal(workflow.nextIntent.bundle, 'do');
119
- assert.equal(workflow.nextIntent.targetRuntimeStage, 'do');
120
- assert.equal(workflow.recommendedNextCommand, 'sdd do task <task_id> --branch feature');
121
- assert.equal(workflow.truthReconciliation?.changeKind, 'implementation_mismatch');
122
- assert.deepEqual(workflow.truthReconciliation?.minimalFrontier, ['do', 'test', 'goal-verify', 'ship']);
123
- assert.equal(workflow.truthReconciliation?.preservesEvidenceRefs.length, 0);
124
- assert.equal(workflow.truthReconciliation?.supersedesEvidenceRefs.length, 2);
125
- assert.equal(projection?.payload.nextIntent.canonicalCommand, workflow.nextIntent.canonicalCommand);
126
- assert.equal(workflow.nextIntent.hostProjections.find((host) => host.host === 'claude_code')?.entry, '/sdd:do task <task_id> --branch feature');
127
- assert.equal(workflow.nextIntent.canonicalCommand.includes('sync-back'), false);
128
- } finally {
129
- await rm(root, { recursive: true, force: true });
130
- }
131
- });
132
-
133
- test('workflow state advances material truth reconciliation frontier after do correction evidence', async () => {
134
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-truth-frontier-'));
135
- try {
136
- await initProject(root);
137
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
138
- await recordTruthAlignmentProjection(root, truthAlignmentProjection({
139
- branch: 'feature',
140
- status: 'drift_detected',
141
- ownerStage: 'do',
142
- semanticImpact: 'material',
143
- invalidatesStages: ['do'],
144
- staleRefs: [{ kind: 'artifact', ref: '.sdd/runs/feature/do/implementation-v1.md', hash: 'old-implementation-hash' }],
145
- reasons: ['accepted implementation evidence no longer matches declared truth'],
146
- createdAt: '2020-01-01T00:00:00.000Z'
147
- }));
148
- const run = await createRun(root, { runId: 'run-post-truth-do', branch: 'feature', taskId: 'T1' });
149
- await writeRunState(root, {
150
- ...run,
151
- status: 'completed',
152
- createdAt: '2026-06-01T00:00:01.000Z',
153
- updatedAt: '2026-06-01T00:00:01.000Z',
154
- tasks: {
155
- T1: {
156
- status: 'implemented_pending_validation',
157
- implementationStatus: 'implemented',
158
- verificationStatus: 'not_run',
159
- validationBatch: null,
160
- validationTiming: 'task_end',
161
- requiresVerifyBeforeNext: true,
162
- gaps: [],
163
- artifacts: ['.sdd/runs/feature/do/implementation-v2.md']
164
- }
165
- }
166
- });
167
-
168
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
169
-
170
- assert.equal(workflow.truthReconciliation?.ownerStage, 'do');
171
- assert.deepEqual(workflow.truthReconciliation?.minimalFrontier, ['do', 'test', 'goal-verify', 'ship']);
172
- assert.equal(workflow.nextIntent.intent, 'reconcile_truth');
173
- assert.equal(workflow.nextIntent.bundle, 'test');
174
- assert.equal(workflow.nextIntent.targetRuntimeStage, 'test');
175
- assert.equal(workflow.recommendedNextCommand, 'sdd test close --branch feature --compact-json');
176
- assert.equal(workflow.nextIntent.canonicalCommand.includes('sync-back'), false);
177
- } finally {
178
- await rm(root, { recursive: true, force: true });
179
- }
180
- });
181
-
182
- test('workflow state advances material truth reconciliation frontier after test stage close', async () => {
183
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-truth-test-frontier-'));
184
- try {
185
- await initProject(root);
186
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
187
- await recordTruthAlignmentProjection(root, truthAlignmentProjection({
188
- branch: 'feature',
189
- status: 'drift_detected',
190
- ownerStage: 'do',
191
- semanticImpact: 'material',
192
- invalidatesStages: ['do'],
193
- staleRefs: [{ kind: 'artifact', ref: '.sdd/runs/feature/do/implementation-v1.md', hash: 'old-implementation-hash' }],
194
- reasons: ['accepted implementation evidence no longer matches declared truth'],
195
- createdAt: '2020-01-01T00:00:00.000Z'
196
- }));
197
- const doRun = await createRun(root, { runId: 'run-post-truth-do', branch: 'feature', taskId: 'T1' });
198
- await writeRunState(root, {
199
- ...doRun,
200
- status: 'completed',
201
- tasks: {
202
- T1: {
203
- status: 'implemented_pending_validation',
204
- implementationStatus: 'implemented',
205
- verificationStatus: 'not_run',
206
- validationBatch: null,
207
- validationTiming: 'task_end',
208
- requiresVerifyBeforeNext: true,
209
- gaps: [],
210
- artifacts: ['.sdd/runs/feature/do/implementation-v2.md']
211
- }
212
- }
213
- });
214
- const acceptedTestRef = { kind: 'artifact' as const, ref: '.sdd/runs/feature/test/validation-v2.md', hash: 'validation-v2-hash' };
215
- const generatedAt = '2026-06-01T00:00:02.000Z';
216
- await recordRuntimeProjectionEnvelope(root, {
217
- projectionType: TEST_COLLABORATION_ADJUDICATION_PROJECTION_TYPE,
218
- scopeKey: testCollaborationScopeKey({ branch: 'feature' }),
219
- inputHash: 'test-adjudication-v2',
220
- producer: 'phase9.6-test-stage-collaboration-runtime',
221
- producerVersion: 'phase9.6-test-stage-collaboration-runtime-v1',
222
- generatedAt,
223
- payload: {
224
- contract: 'phase-9.1-stage-collaboration-runtime-v1',
225
- adjudicationId: 'test-adjudication-v2',
226
- stage: 'test',
227
- scope: { branch: 'feature' },
228
- health: 'ready_for_goal_verify',
229
- stageDecision: {
230
- contract: 'phase-9.1-stage-collaboration-runtime-v1',
231
- decisionId: 'test-stage-decision-v2',
232
- stage: 'test',
233
- scope: { branch: 'feature' },
234
- status: 'completed',
235
- health: 'ready_for_goal_verify',
236
- acceptedDecisionRefs: [acceptedTestRef],
237
- advisoryRefs: [],
238
- capabilityRefs: [],
239
- blockingReasons: [],
240
- createdAt: generatedAt
241
- },
242
- handoffPacket: null,
243
- rejection: null,
244
- nextActions: [],
245
- closureRefs: {
246
- runRef: { kind: 'run', ref: 'run-post-truth-test' },
247
- acceptedTestEvidenceRef: acceptedTestRef,
248
- testAcceptanceStatus: 'accepted',
249
- testEvidenceHash: 'validation-v2-hash',
250
- acceptedDoHandoffRef: null,
251
- artifactRefs: [acceptedTestRef],
252
- collaborationContractRef: null,
253
- lifecycleRiskProjectionRef: { kind: 'projection', ref: 'phase8_lifecycle_risk_decision:feature:all:none:none' },
254
- adjudicationProjectionRef: { kind: 'projection', ref: `${TEST_COLLABORATION_ADJUDICATION_PROJECTION_TYPE}:${testCollaborationScopeKey({ branch: 'feature' })}` },
255
- stageRunProjectionRef: { kind: 'projection', ref: 'phase8_stage_run:feature:all:run-post-truth-test:none:test' },
256
- reasons: []
257
- },
258
- createdAt: generatedAt
259
- }
260
- });
261
-
262
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
263
-
264
- assert.equal(workflow.nextIntent.intent, 'reconcile_truth');
265
- assert.equal(workflow.nextIntent.bundle, 'test');
266
- assert.equal(workflow.nextIntent.targetRuntimeStage, 'goal-verify');
267
- assert.equal(workflow.recommendedNextCommand, 'sdd test close --branch feature --target goal-verify --compact-json');
268
- assert.equal(workflow.nextIntent.canonicalCommand.includes('sync-back'), false);
269
- } finally {
270
- await rm(root, { recursive: true, force: true });
271
- }
272
- });
273
-
274
- test('workflow state maps intra-bundle truth reconciliation to task and test command bundles', async () => {
275
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-truth-bundles-'));
276
- try {
277
- await initProject(root);
278
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
279
- await recordTruthAlignmentProjection(root, truthAlignmentProjection({
280
- branch: 'feature',
281
- status: 'update_required',
282
- ownerStage: 'verifies',
283
- semanticImpact: 'none',
284
- invalidatesStages: ['verifies'],
285
- staleRefs: [{ kind: 'document', ref: 'specs/feature/verify.md', hash: 'old-verify-hash' }],
286
- reasons: ['verify contract needs documentation catch-up']
287
- }));
288
-
289
- const verifiesWorkflow = await resolveWorkflowState(root, { branch: 'feature' });
290
-
291
- assert.equal(verifiesWorkflow.nextIntent.bundle, 'tasks');
292
- assert.equal(verifiesWorkflow.nextIntent.targetRuntimeStage, 'verifies');
293
- assert.equal(verifiesWorkflow.nextIntent.displayCommand, '/sdd:tasks target=verifies close --branch feature --compact-json');
294
- assert.equal(verifiesWorkflow.nextIntent.canonicalCommand, 'sdd tasks close --branch feature --target verifies --compact-json');
295
-
296
- await recordTruthAlignmentProjection(root, truthAlignmentProjection({
297
- branch: 'feature',
298
- status: 'drift_detected',
299
- ownerStage: 'goal-verify',
300
- semanticImpact: 'bounded',
301
- invalidatesStages: ['goal-verify'],
302
- staleRefs: [{ kind: 'projection', ref: 'phase9_12_truth_alignment:feature', hash: 'old-gate-hash' }],
303
- reasons: ['goal verification gate policy changed']
304
- }));
305
-
306
- const goalVerifyWorkflow = await resolveWorkflowState(root, { branch: 'feature' });
307
-
308
- assert.equal(goalVerifyWorkflow.nextIntent.bundle, 'test');
309
- assert.equal(goalVerifyWorkflow.nextIntent.targetRuntimeStage, 'goal-verify');
310
- assert.equal(goalVerifyWorkflow.nextIntent.displayCommand, '/sdd:test target=goal-verify close --branch feature --compact-json');
311
- assert.equal(goalVerifyWorkflow.nextIntent.canonicalCommand, 'sdd test close --branch feature --target goal-verify --compact-json');
312
- assert.equal(goalVerifyWorkflow.nextIntent.canonicalCommand.includes('sync-back'), false);
313
- } finally {
314
- await rm(root, { recursive: true, force: true });
315
- }
316
- });
317
-
318
- test('workflow state routes stale aligned truthAlignment refs to minimal document reconciliation', async () => {
319
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-stale-truth-'));
320
- try {
321
- await initProject(root);
322
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
323
- const specPath = path.join(root, 'specs', 'feature', 'spec.md');
324
- const tasksPath = path.join(root, 'specs', 'feature', 'tasks.md');
325
- const specHash = hashTestDocument(await readFile(specPath, 'utf8'));
326
- const tasksHash = hashTestDocument(await readFile(tasksPath, 'utf8'));
327
- await recordTruthAlignmentProjection(root, {
328
- contract: 'sdd-truth-alignment-v1',
329
- branch: 'feature',
330
- sourceStage: 'goal-verify',
331
- declaredTruthRefs: [
332
- { kind: 'document', ref: 'specs/feature/spec.md', hash: specHash },
333
- { kind: 'document', ref: 'specs/feature/tasks.md', hash: tasksHash }
334
- ],
335
- acceptedRealityRefs: [{ kind: 'artifact', ref: '.sdd/runs/feature/goal-verify/goal-verification-v1.md' }],
336
- status: 'aligned',
337
- ownerStage: null,
338
- semanticImpact: 'none',
339
- staleRefs: [],
340
- invalidatesStages: [],
341
- reasons: ['Accepted goal verification is structurally aligned with declared upstream truth refs.'],
342
- createdAt: '2026-06-01T00:00:00.000Z'
343
- });
344
- await writeFile(tasksPath, `${await readFile(tasksPath, 'utf8')}\nAdditional documentation-only acceptance clarification.\n`, 'utf8');
345
-
346
- const workflow = await resolveWorkflowState(root, { branch: 'feature' });
347
-
348
- assert.equal(workflow.nextIntent.intent, 'reconcile_truth');
349
- assert.equal(workflow.nextIntent.bundle, 'tasks');
350
- assert.equal(workflow.nextIntent.targetRuntimeStage, 'tasks');
351
- assert.equal(workflow.recommendedNextCommand, 'sdd tasks close --branch feature --compact-json');
352
- assert.equal(workflow.truthReconciliation?.changeKind, 'documentation_catchup');
353
- assert.equal(workflow.truthReconciliation?.semanticImpact, 'none');
354
- assert.deepEqual(workflow.truthReconciliation?.minimalFrontier, ['tasks']);
355
- assert.equal(workflow.truthReconciliation?.changedRef.ref, 'specs/feature/tasks.md');
356
- assert.equal(workflow.truthReconciliation?.oldHash, tasksHash);
357
- assert.notEqual(workflow.truthReconciliation?.newHash, tasksHash);
358
- assert.equal(workflow.nextIntent.canonicalCommand.includes('sync-back'), false);
359
- } finally {
360
- await rm(root, { recursive: true, force: true });
361
- }
362
- });
363
-
364
- test('workflow state skips document truth refs already accepted by stage close', async () => {
365
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-stale-truth-close-'));
366
- try {
367
- await initProject(root);
368
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
369
- const specPath = path.join(root, 'specs', 'feature', 'spec.md');
370
- const tasksPath = path.join(root, 'specs', 'feature', 'tasks.md');
371
- const originalSpecHash = hashTestDocument(await readFile(specPath, 'utf8'));
372
- const originalTasksHash = hashTestDocument(await readFile(tasksPath, 'utf8'));
373
- await recordTruthAlignmentProjection(root, {
374
- contract: 'sdd-truth-alignment-v1',
375
- branch: 'feature',
376
- sourceStage: 'goal-verify',
377
- declaredTruthRefs: [
378
- { kind: 'document', ref: 'specs/feature/spec.md', hash: originalSpecHash },
379
- { kind: 'document', ref: 'specs/feature/tasks.md', hash: originalTasksHash }
380
- ],
381
- acceptedRealityRefs: [{ kind: 'artifact', ref: '.sdd/runs/feature/goal-verify/goal-verification-v1.md' }],
382
- status: 'aligned',
383
- ownerStage: null,
384
- semanticImpact: 'none',
385
- staleRefs: [],
386
- invalidatesStages: [],
387
- reasons: ['Accepted goal verification is structurally aligned with declared upstream truth refs.'],
388
- createdAt: '2026-06-01T00:00:00.000Z'
389
- });
390
- await writeFile(specPath, `${await readFile(specPath, 'utf8')}\nSpec documentation-only correction.\n`, 'utf8');
391
- await writeFile(tasksPath, `${await readFile(tasksPath, 'utf8')}\nTasks documentation-only correction.\n`, 'utf8');
392
- const currentSpecHash = hashTestDocument(await readFile(specPath, 'utf8'));
393
- const currentTasksHash = hashTestDocument(await readFile(tasksPath, 'utf8'));
394
- const acceptedSpecRef = { kind: 'document' as const, ref: 'specs/feature/spec.md', hash: currentSpecHash };
395
- const generatedAt = '2026-06-01T00:00:02.000Z';
396
- await recordRuntimeProjectionEnvelope(root, {
397
- projectionType: SPEC_COLLABORATION_ADJUDICATION_PROJECTION_TYPE,
398
- scopeKey: specCollaborationScopeKey({ branch: 'feature' }),
399
- inputHash: 'spec-adjudication-v2',
400
- producer: 'phase9.1-spec-stage-collaboration-runtime',
401
- producerVersion: 'phase9.1-spec-stage-collaboration-runtime-v1',
402
- generatedAt,
403
- payload: {
404
- contract: 'phase-9.1-stage-collaboration-runtime-v1',
405
- adjudicationId: 'spec-adjudication-v2',
406
- stage: 'spec',
407
- scope: { branch: 'feature' },
408
- health: 'ready_for_plan',
409
- stageDecision: {
410
- contract: 'phase-9.1-stage-collaboration-runtime-v1',
411
- decisionId: 'spec-stage-decision-v2',
412
- stage: 'spec',
413
- scope: { branch: 'feature' },
414
- status: 'completed',
415
- health: 'ready_for_plan',
416
- acceptedDecisionRefs: [acceptedSpecRef],
417
- advisoryRefs: [],
418
- capabilityRefs: [],
419
- blockingReasons: [],
420
- createdAt: generatedAt
421
- },
422
- handoffPacket: null,
423
- rejection: null,
424
- nextActions: [],
425
- closureRefs: {
426
- acceptedSpecRef,
427
- specHash: currentSpecHash,
428
- reasons: []
429
- },
430
- createdAt: generatedAt
431
- }
432
- });
433
-
434
- const workflow = await resolveWorkflowState(root, { branch: 'feature' });
435
-
436
- assert.equal(workflow.nextIntent.intent, 'reconcile_truth');
437
- assert.equal(workflow.nextIntent.bundle, 'tasks');
438
- assert.equal(workflow.nextIntent.targetRuntimeStage, 'tasks');
439
- assert.equal(workflow.recommendedNextCommand, 'sdd tasks close --branch feature --compact-json');
440
- assert.equal(workflow.truthReconciliation?.changedRef.ref, 'specs/feature/tasks.md');
441
- assert.equal(workflow.truthReconciliation?.oldHash, originalTasksHash);
442
- assert.equal(workflow.truthReconciliation?.newHash, currentTasksHash);
443
- assert.equal(workflow.truthReconciliation?.reasons.some((reason) => reason.includes('specs/feature/spec.md')), false);
444
- } finally {
445
- await rm(root, { recursive: true, force: true });
446
- }
447
- });
448
-
449
- test('workflow state routes open repairs before repeating do or validation', async () => {
450
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-repair-'));
451
- try {
452
- await initProject(root);
453
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
454
- await recordRuntimeRepair(root, buildOpenRepairRecord({
455
- branchSlug: 'feature',
456
- taskId: 'T1',
457
- message: 'validation command is not directly executable: manual: inspect service',
458
- recommendedCommands: ['sdd doctor --branch feature --latest-only']
459
- }));
460
-
461
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
462
-
463
- assert.equal(workflow.openRepairs.length, 1);
464
- assert.equal(workflow.nextIntent.intent, 'repair_failure');
465
- assert.equal(workflow.recommendedNextCommand, 'sdd doctor --branch feature --latest-only');
466
- assert.equal(workflow.blockingReasons.some((reason) => reason.includes('not directly executable')), true);
467
- } finally {
468
- await rm(root, { recursive: true, force: true });
469
- }
470
- });
471
-
472
- test('workflow state strict stale rejection names tasks contract drift', async () => {
473
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-stale-dimension-'));
474
- try {
475
- await initProject(root);
476
- const originalTasks = validTaskMarkdown('T1', []);
477
- await writeBranchDocs(root, 'feature', originalTasks);
478
- const run = await createRun(root, { runId: 'run-stale-contract' });
479
- await bindTestRunState(root, run.runId, 'feature', 'T1');
480
- await markTestRunReadyForShip(root, run.runId, 'T1');
481
- await writeBranchDocs(root, 'feature', originalTasks.replace('risk: []', 'required_artifacts:\n - artifacts/implement-T1.md\nrisk: []'));
482
-
483
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
484
- const rejected = workflow.latestEligibleRunsByTask.find((selection) => selection.taskId === 'T1')?.rejected.find((candidate) => candidate.runId === 'run-stale-contract');
485
-
486
- assert.equal(workflow.latestRun, null);
487
- assert.equal(rejected?.compatibility, 'strict_stale');
488
- assert.equal(rejected?.reasons.some((reason) => reason.includes('tasks contract hash drift')), true);
489
- } finally {
490
- await rm(root, { recursive: true, force: true });
491
- }
492
- });
493
-
494
-
495
- test('workflow state does not route to ship until every required task has PASS evidence', async () => {
496
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-readiness-'));
497
- try {
498
- await initProject(root);
499
- await writeBranchDocs(root, 'feature', `# Tasks\n\n${validTaskMarkdown('T1', []).replace('packages/core/src/index.ts', 'docs/t1.md')}\n${validTaskMarkdown('T2', []).replace('T1', 'T2').replace('packages/core/src/index.ts', 'docs/t2.md')}`);
500
- const run = await createRun(root, { runId: 'run-t1-pass' });
501
- await bindTestRunState(root, run.runId, 'feature', 'T1');
502
- await markTestRunReadyForShip(root, run.runId, 'T1');
503
-
504
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
505
-
506
- assert.equal(workflow.nextIntent.stage, 'do');
507
- assert.equal(workflow.recommendedNextCommand, 'sdd do task T2 --branch feature');
508
- assert.deepEqual(workflow.workflowReadiness.requiredTaskIds, ['T1', 'T2']);
509
- assert.deepEqual(workflow.workflowReadiness.acceptedTaskIds, ['T1']);
510
- assert.deepEqual(workflow.workflowReadiness.missingTaskIds, ['T2']);
511
- assert.equal(workflow.workflowReadiness.readyForShip, false);
512
- assert.deepEqual(workflow.whyNotShip, ['Task T2 has no accepted validation PASS evidence.']);
513
- } finally {
514
- await rm(root, { recursive: true, force: true });
515
- }
516
- });
517
-
518
- test('workflow state resolver reports affected-file conflicts without run-index rebuild', async () => {
519
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-conflict-'));
520
- try {
521
- await initProject(root);
522
- await writeBranchDocs(root, 'feature', `${validTaskMarkdown('T1', []).replace('packages/core/src/index.ts', 'src/shared.ts')}\n${validTaskMarkdown('T2', []).replace('T1', 'T2').replace('packages/core/src/index.ts', 'src/shared.ts')}`);
523
- const runA = await createRun(root, { runId: 'run-a' });
524
- await bindTestRunState(root, runA.runId, 'feature', 'T1');
525
- await markTestRunReadyForShip(root, runA.runId, 'T1');
526
- const runB = await createRun(root, { runId: 'run-b' });
527
- await bindTestRunState(root, runB.runId, 'feature', 'T2');
528
- const archived = await createRun(root, { runId: 'run-c' });
529
- await writeRunState(root, { ...archived, status: 'archived' });
530
-
531
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
532
-
533
- assert.deepEqual(workflow.affectedFileConflicts.map((entry) => entry.runId), ['run-b']);
534
- assert.equal(workflow.blockingReasons.some((reason) => reason.includes('src/shared.ts')), true);
535
- } finally {
536
- await rm(root, { recursive: true, force: true });
537
- }
538
- });
539
-
540
- test('workflow state ignores superseded failed and foreground observer conflict candidates', async () => {
541
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-filtered-conflicts-'));
542
- try {
543
- await initProject(root);
544
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []).replace('packages/core/src/index.ts', 'docs/t1.md'));
545
- const failed = await createRun(root, { runId: 'run-failed' });
546
- await bindTestRunState(root, failed.runId, 'feature', 'T1');
547
- await writeRunState(root, {
548
- ...await readRunState(root, failed.runId),
549
- status: 'failed',
550
- validation: { status: 'fail', commands: ['npm test'], evidence: [] }
551
- });
552
- const observer = await createRun(root, { runId: 'run-observer' });
553
- await bindTestRunState(root, observer.runId, 'feature', 'T1');
554
- const delegation = createDelegationRecord({
555
- delegationId: 'F-T1-observer-001',
556
- task: 'T1',
557
- agent: 'observer',
558
- runMode: 'foreground',
559
- blocking: false,
560
- requiredForPhaseExit: false,
561
- expectedArtifact: 'artifacts/observer-T1.md'
562
- });
563
- await writeRunState(root, {
564
- ...await readRunState(root, observer.runId),
565
- status: 'completed',
566
- phase: 'foreground-subagents',
567
- delegations: { [delegation.delegationId]: { ...delegation, status: 'COMPLETED', terminalEventAt: new Date().toISOString() } }
568
- });
569
- const retry = await createRun(root, { runId: 'run-retry' });
570
- await bindTestRunState(root, retry.runId, 'feature', 'T1');
571
- await markTestRunReadyForShip(root, retry.runId, 'T1');
572
-
573
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
574
-
575
- assert.equal(workflow.latestRun?.runId, 'run-retry');
576
- assert.deepEqual(workflow.affectedFileConflicts, []);
577
- assert.equal(workflow.blockingReasons.some((reason) => reason.includes('Affected file')), false);
578
- } finally {
579
- await rm(root, { recursive: true, force: true });
580
- }
581
- });
582
-
583
- test('workflow state resolver surfaces dependency blockers and points next action upstream', async () => {
584
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-dependencies-'));
585
- try {
586
- await initProject(root);
587
- await writeBranchDocs(root, 'feature', `# Tasks\n\n${validTaskMarkdown('DEP1', [])}\n${validTaskMarkdown('DEP2', ['DEP1']).replace('packages/core/src/index.ts', 'docs/dep2.md')}`);
588
-
589
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'DEP2' });
590
-
591
- assert.deepEqual(workflow.dependencyBlockers.map((blocker) => `${blocker.taskId}->${blocker.dependencyId}`), ['DEP2->DEP1']);
592
- assert.equal(workflow.blockingReasons.some((reason) => reason.includes('DEP2 depends on DEP1')), true);
593
- assert.equal(workflow.recommendedNextCommand, 'sdd do task DEP1 --branch feature');
594
- } finally {
595
- await rm(root, { recursive: true, force: true });
596
- }
597
- });
598
-
599
- test('workflow state treats implemented batch dependency as ready for downstream do', async () => {
600
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-runtime-dependency-ready-'));
601
- try {
602
- await initProject(root);
603
- await writeBranchDocs(root, 'feature', `# Tasks
604
-
605
- ${validTaskMarkdown('DEP1', [])
606
- .replace('packages/core/src/index.ts', 'docs/dep1.md')
607
- .replace('validation:\n - npm test', 'validation_batch: dep-batch\nvalidation_timing: batch_end\nrequires_verify_before_next: false\nvalidation:\n - npm test')}
608
- ${validTaskMarkdown('DEP2', ['DEP1'])
609
- .replace('packages/core/src/index.ts', 'docs/dep2.md')
610
- .replace('validation:\n - npm test', 'validation_batch: dep-batch\nvalidation_timing: batch_end\nrequires_verify_before_next: false\nvalidation:\n - npm test')}`);
611
- const run = await createRun(root, { runId: 'run-dep1-implemented' });
612
- await bindTestRunState(root, run.runId, 'feature', 'DEP1');
613
- const bound = await readRunState(root, run.runId);
614
- await writeRunState(root, {
615
- ...bound,
616
- status: 'completed',
617
- tasks: {
618
- ...bound.tasks,
619
- DEP1: {
620
- status: 'implemented_pending_validation',
621
- implementationStatus: 'implemented',
622
- verificationStatus: 'pending_batch',
623
- validationBatch: 'dep-batch',
624
- validationTiming: 'batch_end',
625
- requiresVerifyBeforeNext: false,
626
- gaps: [],
627
- artifacts: []
628
- }
629
- }
630
- });
631
-
632
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'DEP2' });
633
-
634
- assert.deepEqual(workflow.dependencyBlockers, []);
635
- assert.equal(workflow.recommendedNextCommand, 'sdd do task DEP2 --branch feature');
636
- } finally {
637
- await rm(root, { recursive: true, force: true });
638
- }
639
- });
640
-
641
- test('workflow state blocks downstream do until strict dependency verification passes', async () => {
642
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-runtime-dependency-strict-'));
643
- try {
644
- await initProject(root);
645
- await writeBranchDocs(root, 'feature', `# Tasks
646
-
647
- ${validTaskMarkdown('DEP1', [])
648
- .replace('packages/core/src/index.ts', 'docs/dep1.md')
649
- .replace('validation:\n - npm test', 'validation_timing: task_end\nrequires_verify_before_next: true\nvalidation:\n - npm test')}
650
- ${validTaskMarkdown('DEP2', ['DEP1']).replace('packages/core/src/index.ts', 'docs/dep2.md')}`);
651
- const run = await createRun(root, { runId: 'run-dep1-strict-implemented' });
652
- await bindTestRunState(root, run.runId, 'feature', 'DEP1');
653
- const bound = await readRunState(root, run.runId);
654
- await writeRunState(root, {
655
- ...bound,
656
- status: 'completed',
657
- tasks: {
658
- ...bound.tasks,
659
- DEP1: {
660
- status: 'implemented_pending_validation',
661
- implementationStatus: 'implemented',
662
- verificationStatus: 'not_run',
663
- validationBatch: null,
664
- validationTiming: 'task_end',
665
- requiresVerifyBeforeNext: true,
666
- gaps: [],
667
- artifacts: []
668
- }
669
- }
670
- });
671
-
672
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'DEP2' });
673
-
674
- assert.deepEqual(workflow.dependencyBlockers.map((blocker) => `${blocker.taskId}->${blocker.dependencyId}`), ['DEP2->DEP1']);
675
- assert.equal(workflow.blockingReasons.some((reason) => reason.includes('has not passed required verification')), true);
676
- assert.equal(workflow.recommendedNextCommand, 'sdd test task-DEP1 --branch feature');
677
- } finally {
678
- await rm(root, { recursive: true, force: true });
679
- }
680
- });
681
-
682
-
683
- test('latest eligible selector prefers older compatible evidence over newer strict-stale evidence', async () => {
684
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-eligible-'));
685
- try {
686
- await initProject(root);
687
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
688
- const compatible = await createRun(root, { runId: 'run-compatible' });
689
- await bindTestRunState(root, compatible.runId, 'feature', 'T1');
690
- await markTestRunReadyForShip(root, compatible.runId, 'T1');
691
-
692
- const strictStale = await createRun(root, { runId: 'run-strict-stale' });
693
- await bindTestRunState(root, strictStale.runId, 'feature', 'T1');
694
- await markTestRunReadyForShip(root, strictStale.runId, 'T1');
695
- const strictStaleState = await readRunState(root, strictStale.runId);
696
- await writeRunState(root, {
697
- ...strictStaleState,
698
- documentSnapshot: {
699
- ...strictStaleState.documentSnapshot,
700
- tasksContractHash: 'stale-tasks-contract-hash',
701
- taskContractHash: 'stale-task-contract-hash',
702
- }
703
- });
704
-
705
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
706
- const selection = workflow.latestEligibleRunsByTask.find((entry) => entry.taskId === 'T1');
707
-
708
- assert.equal(workflow.latestRun?.runId, 'run-compatible');
709
- assert.equal(selection?.selected?.runId, 'run-compatible');
710
- assert.deepEqual(selection?.rejected.map((entry) => `${entry.runId}:${entry.compatibility}`), ['run-strict-stale:strict_stale']);
711
- assert.equal(selection?.rejected[0]?.reasons.some((reason) => reason.includes('strict_stale')), true);
712
- } finally {
713
- await rm(root, { recursive: true, force: true });
714
- }
715
- });
716
-
717
- test('latest eligible selector keeps task-local evidence when another task changes', async () => {
718
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-task-local-eligible-'));
719
- try {
720
- await initProject(root);
721
- const task1 = validTaskMarkdown('T1', []).replace('packages/core/src/index.ts', 'docs/t1.md');
722
- const task2 = validTaskMarkdown('T2', []).replace('T1', 'T2').replace('packages/core/src/index.ts', 'docs/t2.md');
723
- await writeBranchDocs(root, 'feature', `# Tasks\n\n${task1}\n${task2}`);
724
- const run = await createRun(root, { runId: 'run-t1-compatible' });
725
- await bindTestRunState(root, run.runId, 'feature', 'T1');
726
- await markTestRunReadyForShip(root, run.runId, 'T1');
727
- await writeBranchDocs(root, 'feature', `# Tasks\n\n${task1}\n${task2.replace('risk: []', 'risk:\n - security')}`);
728
-
729
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
730
- const selection = workflow.latestEligibleRunsByTask.find((entry) => entry.taskId === 'T1');
731
-
732
- assert.equal(workflow.latestRun?.runId, 'run-t1-compatible');
733
- assert.equal(selection?.selected?.runId, 'run-t1-compatible');
734
- assert.deepEqual(selection?.rejected.map((entry) => entry.runId), []);
735
- } finally {
736
- await rm(root, { recursive: true, force: true });
737
- }
738
- });
739
-
740
- test('latest eligible selector rejects newer blocked runs and keeps older completed evidence eligible', async () => {
741
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-blocked-eligible-'));
742
- try {
743
- await initProject(root);
744
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
745
- const completed = await createRun(root, { runId: 'run-completed' });
746
- await bindTestRunState(root, completed.runId, 'feature', 'T1');
747
- await markTestRunReadyForShip(root, completed.runId, 'T1');
748
-
749
- const blocked = await createRun(root, { runId: 'run-blocked' });
750
- await bindTestRunState(root, blocked.runId, 'feature', 'T1');
751
- await markTestRunReadyForShip(root, blocked.runId, 'T1');
752
- await writeRunState(root, { ...await readRunState(root, blocked.runId), status: 'blocked' });
753
-
754
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
755
- const selection = workflow.latestEligibleRunsByTask.find((entry) => entry.taskId === 'T1');
756
-
757
- assert.equal(selection?.selected?.runId, 'run-completed');
758
- assert.equal(selection?.rejected.some((entry) => entry.runId === 'run-blocked' && entry.reasons.includes('Run is blocked.')), true);
759
- } finally {
760
- await rm(root, { recursive: true, force: true });
761
- }
762
- });
763
-
764
- test('latest eligible selector returns visible candidates and rejects archived or failed runs with reasons', async () => {
765
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-rejected-'));
766
- try {
767
- await initProject(root);
768
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
769
- const failed = await createRun(root, { runId: 'run-failed' });
770
- await bindTestRunState(root, failed.runId, 'feature', 'T1');
771
- await writeRunState(root, {
772
- ...await readRunState(root, failed.runId),
773
- status: 'failed',
774
- validation: { status: 'fail', commands: ['npm test'], evidence: [] }
775
- });
776
- const archived = await createRun(root, { runId: 'run-archived' });
777
- await bindTestRunState(root, archived.runId, 'feature', 'T1');
778
- await writeRunState(root, { ...await readRunState(root, archived.runId), status: 'archived' });
779
-
780
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
781
- const selection = workflow.latestEligibleRunsByTask.find((entry) => entry.taskId === 'T1');
782
-
783
- assert.equal(workflow.latestRun, null);
784
- assert.deepEqual(selection?.candidates.map((entry) => entry.runId), ['run-failed']);
785
- assert.deepEqual(selection?.rejected.map((entry) => entry.runId).sort(), ['run-archived', 'run-failed']);
786
- assert.equal(selection?.rejected.some((entry) => entry.reasons.includes('Run failed.')), true);
787
- assert.equal(selection?.rejected.some((entry) => entry.reasons.includes('Run is archived.')), true);
788
- } finally {
789
- await rm(root, { recursive: true, force: true });
790
- }
791
- });
792
-
793
- test('workflow state uses explicit partition runtime despite divergent git branch', async () => {
794
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-divergent-'));
795
- try {
796
- await initProject(root);
797
- await execFileAsync('git', ['init'], { cwd: root });
798
- await execFileAsync('git', ['checkout', '-b', 'current-branch'], { cwd: root });
799
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', [])
800
- .replace('packages/core/src/index.ts', 'docs/t1.md')
801
- .replace('validation:\n - npm test', 'validation_timing: task_end\nrequires_verify_before_next: true\nvalidation:\n - npm test'));
802
- const divergent = await createRun(root, { runId: 'run-divergent' });
803
- await bindTestRunState(root, divergent.runId, 'feature', 'T1');
804
- const bound = await readRunState(root, divergent.runId);
805
- await writeRunState(root, {
806
- ...bound,
807
- status: 'completed',
808
- tasks: {
809
- ...bound.tasks,
810
- T1: {
811
- status: 'implemented_pending_validation',
812
- implementationStatus: 'implemented',
813
- verificationStatus: 'not_run',
814
- validationBatch: null,
815
- validationTiming: 'task_end',
816
- requiresVerifyBeforeNext: true,
817
- gaps: [],
818
- artifacts: []
819
- }
820
- }
821
- });
822
-
823
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
824
- const selection = workflow.latestEligibleRunsByTask.find((entry) => entry.taskId === 'T1');
825
-
826
- assert.equal(workflow.latestRun?.runId, 'run-divergent');
827
- assert.equal(selection?.selected?.runId, 'run-divergent');
828
- assert.deepEqual(selection?.rejected.map((entry) => entry.runId), []);
829
- assert.equal(workflow.nextIntent.intent, 'run_task_validation');
830
- assert.equal(workflow.recommendedNextCommand, 'sdd test task-T1 --branch feature');
831
- } finally {
832
- await rm(root, { recursive: true, force: true });
833
- }
834
- });
835
-
836
- test('workflow state recommends wave validation for implemented wave_end boundary', async () => {
837
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-wave-boundary-'));
838
- try {
839
- await initProject(root);
840
- await writeBranchDocs(root, 'feature', `# Tasks
841
-
842
- ${validTaskMarkdown('W1', [])
843
- .replace('packages/core/src/index.ts', 'docs/w1.md')
844
- .replace('validation:\n - npm test', 'validation_batch: docs-wave\nvalidation_timing: wave_end\nrequires_verify_before_next: false\nvalidation:\n - npm test')}`);
845
- const run = await createRun(root, { runId: 'run-w1-implemented' });
846
- await bindTestRunState(root, run.runId, 'feature', 'W1');
847
- const bound = await readRunState(root, run.runId);
848
- await writeRunState(root, {
849
- ...bound,
850
- status: 'completed',
851
- tasks: {
852
- ...bound.tasks,
853
- W1: {
854
- status: 'implemented_pending_validation',
855
- implementationStatus: 'implemented',
856
- verificationStatus: 'pending_batch',
857
- validationBatch: 'docs-wave',
858
- validationTiming: 'wave_end',
859
- requiresVerifyBeforeNext: false,
860
- gaps: [],
861
- artifacts: []
862
- }
863
- }
864
- });
865
-
866
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'W1' });
867
-
868
- assert.equal(workflow.nextIntent.intent, 'run_wave_validation');
869
- assert.equal(workflow.recommendedNextCommand, 'sdd test docs-wave --branch feature');
870
- } finally {
871
- await rm(root, { recursive: true, force: true });
872
- }
873
- });
874
-
875
- test('workflow state dependency readiness ignores newer ineligible runtime state', async () => {
876
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-eligible-runtime-'));
877
- try {
878
- await initProject(root);
879
- await writeBranchDocs(root, 'feature', `# Tasks
880
-
881
- ${validTaskMarkdown('DEP1', [])
882
- .replace('packages/core/src/index.ts', 'docs/dep1.md')
883
- .replace('validation:\n - npm test', 'validation_batch: dep-batch\nvalidation_timing: batch_end\nrequires_verify_before_next: false\nvalidation:\n - npm test')}
884
- ${validTaskMarkdown('DEP2', ['DEP1']).replace('packages/core/src/index.ts', 'docs/dep2.md')}`);
885
- const eligible = await createRun(root, { runId: 'run-dep1-eligible' });
886
- await bindTestRunState(root, eligible.runId, 'feature', 'DEP1');
887
- const eligibleState = await readRunState(root, eligible.runId);
888
- await writeRunState(root, {
889
- ...eligibleState,
890
- status: 'completed',
891
- tasks: {
892
- ...eligibleState.tasks,
893
- DEP1: {
894
- status: 'implemented_pending_validation',
895
- implementationStatus: 'implemented',
896
- verificationStatus: 'pending_batch',
897
- validationBatch: 'dep-batch',
898
- validationTiming: 'batch_end',
899
- requiresVerifyBeforeNext: false,
900
- gaps: [],
901
- artifacts: []
902
- }
903
- }
904
- });
905
- const blocked = await createRun(root, { runId: 'run-dep1-blocked-newer' });
906
- await bindTestRunState(root, blocked.runId, 'feature', 'DEP1');
907
- const blockedState = await readRunState(root, blocked.runId);
908
- await writeRunState(root, {
909
- ...blockedState,
910
- status: 'blocked',
911
- updatedAt: new Date(Date.parse(eligibleState.updatedAt) + 1000).toISOString(),
912
- tasks: {
913
- ...blockedState.tasks,
914
- DEP1: {
915
- status: 'pending',
916
- implementationStatus: 'not_started',
917
- verificationStatus: 'not_run',
918
- validationBatch: 'dep-batch',
919
- validationTiming: 'batch_end',
920
- requiresVerifyBeforeNext: false,
921
- gaps: [],
922
- artifacts: []
923
- }
924
- }
925
- });
926
-
927
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'DEP2' });
928
-
929
- assert.deepEqual(workflow.dependencyBlockers, []);
930
- assert.equal(workflow.recommendedNextCommand, 'sdd test dep-batch --branch feature');
931
- } finally {
932
- await rm(root, { recursive: true, force: true });
933
- }
934
- });
935
-
936
- function truthAlignmentProjection(input: Pick<TruthAlignmentProjection, 'branch' | 'status' | 'ownerStage' | 'semanticImpact' | 'invalidatesStages' | 'staleRefs' | 'reasons'> & { createdAt?: string }): TruthAlignmentProjection {
937
- return {
938
- contract: 'sdd-truth-alignment-v1',
939
- branch: input.branch,
940
- sourceStage: 'goal-verify',
941
- declaredTruthRefs: [
942
- { kind: 'document', ref: `specs/${input.branch}/spec.md`, hash: 'spec-hash' },
943
- { kind: 'document', ref: `specs/${input.branch}/tasks.md`, hash: 'tasks-hash' }
944
- ],
945
- acceptedRealityRefs: [
946
- { kind: 'artifact', ref: `.sdd/runs/${input.branch}/goal-verify/goal-verification-v1.md`, hash: 'goal-hash' },
947
- { kind: 'artifact', ref: `.sdd/runs/${input.branch}/do/implementation-v1.md`, hash: 'implementation-hash' }
948
- ],
949
- status: input.status,
950
- ownerStage: input.ownerStage,
951
- semanticImpact: input.semanticImpact,
952
- staleRefs: input.staleRefs,
953
- invalidatesStages: input.invalidatesStages,
954
- reasons: input.reasons,
955
- createdAt: input.createdAt ?? '2026-06-01T00:00:00.000Z'
956
- };
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
4
+ import { tmpdir } from 'node:os';
5
+ import path from 'node:path';
6
+ import { execFile } from 'node:child_process';
7
+ import { promisify } from 'node:util';
8
+
9
+ import { initProject } from '../config/init-project.js';
10
+ import { createRun, readRunState, writeRunState } from '../run-state/run-state.js';
11
+ import { hashTestDocument, validTaskMarkdown, writeBranchDocs } from '../test-support/fixtures.js';
12
+ import { bindTestRunState, markTestRunReadyForShip } from '../test-support/run-state.js';
13
+ import { createDelegationRecord } from '../delegation/validation.js';
14
+ import { recordRuntimeProjectionEnvelope, recordRuntimeRepair } from '../storage/runtime-store.js';
15
+ import { buildOpenRepairRecord } from './repair-contract.js';
16
+ import { recordLifecycleGraphBundle } from '../lifecycle-graph.js';
17
+ import { evaluateLifecycleRiskDecisionForModel, recordLifecycleRiskDecisionProjection } from '../risk.js';
18
+ import { parseSddBranch } from '../sdd-docs.js';
19
+ import { EXECUTE_COLLABORATION_ADJUDICATION_PROJECTION_TYPE, executeCollaborationScopeKey, recordTruthAlignmentProjection, SPEC_COLLABORATION_ADJUDICATION_PROJECTION_TYPE, specCollaborationScopeKey, type TruthAlignmentProjection } from '../stage-collaboration.js';
20
+ import { readTruthReconciliationProjection } from '../truth-reconciliation.js';
21
+ import { resolveWorkflowState } from './resolve.js';
22
+ import { readNextIntentProjection, readTaskOrchestrationProjection, readValidationUnitProjection, readWorkflowCurrentStateProjection } from './runtime-projections.js';
23
+
24
+ const execFileAsync = promisify(execFile);
25
+
26
+ async function seedLifecycleRiskDecision(projectRoot: string, branch: string, activeStage: Parameters<typeof recordLifecycleGraphBundle>[2] extends { activeStage?: infer T } ? T : never = 'execute' as never): Promise<void> {
27
+ const model = await parseSddBranch(projectRoot, branch);
28
+ const decision = evaluateLifecycleRiskDecisionForModel(branch, model);
29
+ await recordLifecycleRiskDecisionProjection(projectRoot, decision);
30
+ await recordLifecycleGraphBundle(projectRoot, decision, { activeStage });
31
+ }
32
+
33
+ test('workflow state resolver projects branch docs latest run and next action', async () => {
34
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-'));
35
+ try {
36
+ await initProject(root);
37
+ await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
38
+ const run = await createRun(root, { runId: 'run-1' });
39
+ await bindTestRunState(root, run.runId, 'feature', 'T1');
40
+ await markTestRunReadyForShip(root, run.runId, 'T1');
41
+
42
+ const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
43
+
44
+ assert.equal(workflow.contract, 'phase-7.3-workflow-state-resolver-v1');
45
+ assert.equal(workflow.workflowStatus, 'active');
46
+ assert.equal(workflow.latestRun?.runId, 'run-1');
47
+ assert.deepEqual(workflow.latestRunsByTask.map((entry) => `${entry.partition}:${entry.taskId}:${entry.runId}`), ['feature:T1:run-1']);
48
+ assert.equal(workflow.taskCounts.total, 1);
49
+ assert.equal(workflow.recommendedNextCommand, 'sdd ship close --branch feature --compact-json');
50
+ assert.equal(workflow.nextIntent.bundle, 'ship');
51
+ assert.equal(workflow.nextIntent.targetRuntimeStage, 'ship');
52
+ assert.equal(workflow.nextIntent.hostProjections.find((projection) => projection.host === 'claude_code')?.entry, '/sdd:ship close --branch feature --compact-json');
53
+ const currentStateProjection = await readWorkflowCurrentStateProjection(root, 'feature');
54
+ const nextIntentProjection = await readNextIntentProjection(root, 'feature');
55
+ const taskOrchestrationProjection = await readTaskOrchestrationProjection(root, 'feature');
56
+ const validationUnitProjection = await readValidationUnitProjection(root, 'feature');
57
+
58
+ assert.equal(currentStateProjection?.payload.contract, 'sdd-workflow-current-state-projection-v1');
59
+ assert.equal(currentStateProjection?.payload.lifecycle.currentStage, 'ship');
60
+ assert.equal(currentStateProjection?.payload.lifecycle.writer, 'runtime_sqlite');
61
+ assert.equal(currentStateProjection?.payload.tasks[0]?.taskId, 'T1');
62
+ assert.equal(currentStateProjection?.payload.tasks[0]?.consumability, 'consumable');
63
+ assert.equal(currentStateProjection?.payload.validationUnits[0]?.validationUnitId, 'T1');
64
+ assert.equal(taskOrchestrationProjection?.payload.contract, 'sdd-task-orchestration-projection-v1');
65
+ assert.equal(taskOrchestrationProjection?.payload.tasks[0]?.taskId, 'T1');
66
+ assert.equal(taskOrchestrationProjection?.payload.tasks[0]?.sourceRef.ref, 'specs/feature/tasks.md#T1');
67
+ assert.equal(validationUnitProjection?.payload.contract, 'sdd-validation-unit-projection-v1');
68
+ assert.deepEqual(validationUnitProjection?.payload.validationUnits[0]?.taskIds, ['T1']);
69
+ assert.equal(nextIntentProjection?.payload.contract, 'sdd-next-intent-projection-v1');
70
+ assert.equal(nextIntentProjection?.payload.advisory, true);
71
+ assert.equal(nextIntentProjection?.payload.rules.recommendationIsNotAGate, true);
72
+ assert.equal(nextIntentProjection?.payload.primary.canonicalCommand, workflow.nextIntent.canonicalCommand);
73
+ assert.equal(nextIntentProjection?.payload.primary.targetRuntimeStage, 'ship');
74
+ } finally {
75
+ await rm(root, { recursive: true, force: true });
76
+ }
77
+ });
78
+
79
+ test('workflow state routes validation PASS through execute before ship readiness', async () => {
80
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-test-pass-'));
81
+ try {
82
+ await initProject(root);
83
+ await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
84
+ await seedLifecycleRiskDecision(root, 'feature', 'execute');
85
+ const run = await createRun(root, { runId: 'run-pass-no-syncback' });
86
+ await bindTestRunState(root, run.runId, 'feature', 'T1');
87
+ const bound = await readRunState(root, run.runId);
88
+ await writeRunState(root, {
89
+ ...bound,
90
+ status: 'completed',
91
+ validation: {
92
+ status: 'pass',
93
+ commands: ['npm test'],
94
+ evidence: ['artifacts/validation-T1.md']
95
+ }
96
+ });
97
+
98
+ const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
99
+
100
+ assert.equal(workflow.nextIntent.stage, 'execute');
101
+ assert.equal(workflow.nextIntent.bundle, 'execute');
102
+ assert.equal(workflow.nextIntent.targetRuntimeStage, 'execute');
103
+ assert.equal(workflow.nextIntent.intent, 'continue_execute');
104
+ assert.equal(workflow.recommendedNextCommand, 'sdd execute close --branch feature --compact-json');
105
+ } finally {
106
+ await rm(root, { recursive: true, force: true });
107
+ }
108
+ });
109
+
110
+ test.skip('workflow state routes non-aligned truthAlignment to owner stage-manager reconciliation', async () => {
111
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-truth-reconcile-'));
112
+ try {
113
+ await initProject(root);
114
+ await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
115
+ await seedLifecycleRiskDecision(root, 'feature', 'execute');
116
+ await recordTruthAlignmentProjection(root, truthAlignmentProjection({
117
+ branch: 'feature',
118
+ status: 'drift_detected',
119
+ ownerStage: 'execute',
120
+ semanticImpact: 'material',
121
+ invalidatesStages: ['execute'],
122
+ staleRefs: [{ kind: 'artifact', ref: '.sdd/runs/feature/execute/implementation-v1.md', hash: 'old-implementation-hash' }],
123
+ reasons: ['accepted implementation evidence no longer matches declared truth']
124
+ }));
125
+
126
+ const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
127
+ const projection = await readTruthReconciliationProjection(root, 'feature');
128
+
129
+ assert.equal(workflow.nextIntent.intent, 'reconcile_truth');
130
+ assert.equal(workflow.nextIntent.bundle, 'execute');
131
+ assert.equal(workflow.nextIntent.targetRuntimeStage, 'execute');
132
+ assert.equal(workflow.recommendedNextCommand, 'sdd execute close --branch feature --compact-json');
133
+ assert.equal(workflow.truthReconciliation?.changeKind, 'validation_mismatch');
134
+ assert.deepEqual(workflow.truthReconciliation?.minimalFrontier, ['execute', 'ship']);
135
+ assert.equal(workflow.truthReconciliation?.preservesEvidenceRefs.length, 0);
136
+ assert.equal(workflow.truthReconciliation?.supersedesEvidenceRefs.length, 2);
137
+ assert.equal(projection?.payload.nextIntent.canonicalCommand, workflow.nextIntent.canonicalCommand);
138
+ assert.equal(workflow.nextIntent.hostProjections.find((host) => host.host === 'claude_code')?.entry, '/sdd:execute close --branch feature --compact-json');
139
+ assert.equal(workflow.nextIntent.canonicalCommand.includes('sync-back'), false);
140
+ } finally {
141
+ await rm(root, { recursive: true, force: true });
142
+ }
143
+ });
144
+
145
+ test('workflow state advances material truth reconciliation frontier after do correction evidence', async () => {
146
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-truth-frontier-'));
147
+ try {
148
+ await initProject(root);
149
+ await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
150
+ await seedLifecycleRiskDecision(root, 'feature', 'execute');
151
+ await recordTruthAlignmentProjection(root, truthAlignmentProjection({
152
+ branch: 'feature',
153
+ status: 'drift_detected',
154
+ ownerStage: 'execute',
155
+ semanticImpact: 'material',
156
+ invalidatesStages: ['execute'],
157
+ staleRefs: [{ kind: 'artifact', ref: '.sdd/runs/feature/execute/implementation-v1.md', hash: 'old-implementation-hash' }],
158
+ reasons: ['accepted implementation evidence no longer matches declared truth'],
159
+ createdAt: '2020-01-01T00:00:00.000Z'
160
+ }));
161
+ const run = await createRun(root, { runId: 'run-post-truth-do', branch: 'feature', taskId: 'T1' });
162
+ await writeRunState(root, {
163
+ ...run,
164
+ status: 'completed',
165
+ createdAt: '2026-06-01T00:00:01.000Z',
166
+ updatedAt: '2026-06-01T00:00:01.000Z',
167
+ tasks: {
168
+ T1: {
169
+ status: 'implemented_pending_validation',
170
+ implementationStatus: 'implemented',
171
+ verificationStatus: 'not_run',
172
+ validationBatch: null,
173
+ validationTiming: 'task_end',
174
+ requiresVerifyBeforeNext: true,
175
+ gaps: [],
176
+ artifacts: ['.sdd/runs/feature/execute/implementation-v2.md']
177
+ }
178
+ }
179
+ });
180
+
181
+ const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
182
+
183
+ assert.equal(workflow.truthReconciliation?.ownerStage, 'execute');
184
+ assert.deepEqual(workflow.truthReconciliation?.minimalFrontier, ['execute', 'ship']);
185
+ assert.equal(workflow.nextIntent.intent, 'reconcile_truth');
186
+ assert.equal(workflow.nextIntent.bundle, 'execute');
187
+ assert.equal(workflow.nextIntent.targetRuntimeStage, 'execute');
188
+ assert.equal(workflow.recommendedNextCommand, 'sdd execute close --branch feature --compact-json');
189
+ assert.equal(workflow.nextIntent.canonicalCommand.includes('sync-back'), false);
190
+ } finally {
191
+ await rm(root, { recursive: true, force: true });
192
+ }
193
+ });
194
+
195
+ test('workflow state advances material truth reconciliation frontier after execute stage close', async () => {
196
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-truth-test-frontier-'));
197
+ try {
198
+ await initProject(root);
199
+ await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
200
+ await seedLifecycleRiskDecision(root, 'feature', 'execute');
201
+ await recordTruthAlignmentProjection(root, truthAlignmentProjection({
202
+ branch: 'feature',
203
+ status: 'drift_detected',
204
+ ownerStage: 'execute',
205
+ semanticImpact: 'material',
206
+ invalidatesStages: ['execute'],
207
+ staleRefs: [{ kind: 'artifact', ref: '.sdd/runs/feature/execute/implementation-v1.md', hash: 'old-implementation-hash' }],
208
+ reasons: ['accepted implementation evidence no longer matches declared truth'],
209
+ createdAt: '2020-01-01T00:00:00.000Z'
210
+ }));
211
+ const doRun = await createRun(root, { runId: 'run-post-truth-do', branch: 'feature', taskId: 'T1' });
212
+ await writeRunState(root, {
213
+ ...doRun,
214
+ status: 'completed',
215
+ tasks: {
216
+ T1: {
217
+ status: 'implemented_pending_validation',
218
+ implementationStatus: 'implemented',
219
+ verificationStatus: 'not_run',
220
+ validationBatch: null,
221
+ validationTiming: 'task_end',
222
+ requiresVerifyBeforeNext: true,
223
+ gaps: [],
224
+ artifacts: ['.sdd/runs/feature/execute/implementation-v2.md']
225
+ }
226
+ }
227
+ });
228
+ const acceptedExecuteRef = { kind: 'artifact' as const, ref: '.sdd/runs/feature/execute/validation-v2.md', hash: 'validation-v2-hash' };
229
+ const generatedAt = '2026-06-01T00:00:02.000Z';
230
+ await recordRuntimeProjectionEnvelope(root, {
231
+ projectionType: EXECUTE_COLLABORATION_ADJUDICATION_PROJECTION_TYPE,
232
+ scopeKey: executeCollaborationScopeKey({ branch: 'feature' }),
233
+ inputHash: 'execute-adjudication-v2',
234
+ producer: 'phase10-execute-collaboration-runtime',
235
+ producerVersion: 'phase10-execute-collaboration-runtime-v1',
236
+ generatedAt,
237
+ payload: {
238
+ contract: 'phase-9.1-stage-collaboration-runtime-v1',
239
+ adjudicationId: 'execute-adjudication-v2',
240
+ stage: 'execute',
241
+ scope: { branch: 'feature' },
242
+ health: 'ready_for_ship',
243
+ stageDecision: {
244
+ contract: 'phase-9.1-stage-collaboration-runtime-v1',
245
+ decisionId: 'execute-stage-decision-v2',
246
+ stage: 'execute',
247
+ scope: { branch: 'feature' },
248
+ status: 'completed',
249
+ health: 'ready_for_ship',
250
+ acceptedDecisionRefs: [acceptedExecuteRef],
251
+ advisoryRefs: [],
252
+ capabilityRefs: [],
253
+ blockingReasons: [],
254
+ createdAt: generatedAt
255
+ },
256
+ handoffPacket: null,
257
+ rejection: null,
258
+ nextActions: [],
259
+ closureRefs: {
260
+ runRef: { kind: 'run', ref: 'run-post-truth-execute' },
261
+ acceptedExecuteRef,
262
+ executeAcceptanceStatus: 'accepted',
263
+ artifactRefs: [acceptedExecuteRef],
264
+ collaborationContractRef: null,
265
+ lifecycleRiskProjectionRef: { kind: 'projection', ref: 'phase8_lifecycle_risk_decision:feature:all:none:none' },
266
+ adjudicationProjectionRef: { kind: 'projection', ref: `${EXECUTE_COLLABORATION_ADJUDICATION_PROJECTION_TYPE}:${executeCollaborationScopeKey({ branch: 'feature' })}` },
267
+ stageRunProjectionRef: { kind: 'projection', ref: 'phase8_stage_run:feature:all:run-post-truth-execute:none:execute' },
268
+ reasons: []
269
+ },
270
+ createdAt: generatedAt
271
+ }
272
+ });
273
+
274
+ const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
275
+
276
+ assert.equal(workflow.nextIntent.intent, 'reconcile_truth');
277
+ assert.equal(workflow.nextIntent.bundle, 'ship');
278
+ assert.equal(workflow.nextIntent.targetRuntimeStage, 'ship');
279
+ assert.equal(workflow.recommendedNextCommand, 'sdd ship close --branch feature --compact-json');
280
+ assert.equal(workflow.nextIntent.canonicalCommand.includes('sync-back'), false);
281
+ } finally {
282
+ await rm(root, { recursive: true, force: true });
283
+ }
284
+ });
285
+
286
+ test('workflow state maps intra-bundle truth reconciliation to task and execute command bundles', async () => {
287
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-truth-bundles-'));
288
+ try {
289
+ await initProject(root);
290
+ await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
291
+ await seedLifecycleRiskDecision(root, 'feature', 'execute');
292
+ await recordTruthAlignmentProjection(root, truthAlignmentProjection({
293
+ branch: 'feature',
294
+ status: 'update_required',
295
+ ownerStage: 'tasks',
296
+ semanticImpact: 'none',
297
+ invalidatesStages: ['tasks'],
298
+ staleRefs: [{ kind: 'document', ref: 'specs/feature/verify.md', hash: 'old-verify-hash' }],
299
+ reasons: ['verify contract needs documentation catch-up']
300
+ }));
301
+
302
+ const verifiesWorkflow = await resolveWorkflowState(root, { branch: 'feature' });
303
+
304
+ assert.equal(verifiesWorkflow.nextIntent.bundle, 'tasks');
305
+ assert.equal(verifiesWorkflow.nextIntent.targetRuntimeStage, 'tasks');
306
+ assert.equal(verifiesWorkflow.nextIntent.displayCommand, '/sdd:tasks close --branch feature --compact-json');
307
+ assert.equal(verifiesWorkflow.nextIntent.canonicalCommand, 'sdd tasks close --branch feature --compact-json');
308
+
309
+ await recordTruthAlignmentProjection(root, truthAlignmentProjection({
310
+ branch: 'feature',
311
+ status: 'drift_detected',
312
+ ownerStage: 'execute',
313
+ semanticImpact: 'bounded',
314
+ invalidatesStages: ['execute'],
315
+ staleRefs: [{ kind: 'projection', ref: 'phase9_12_truth_alignment:feature', hash: 'old-gate-hash' }],
316
+ reasons: ['execute evidence judgment policy changed']
317
+ }));
318
+
319
+ const goalVerifyWorkflow = await resolveWorkflowState(root, { branch: 'feature' });
320
+
321
+ assert.equal(goalVerifyWorkflow.nextIntent.bundle, 'execute');
322
+ assert.equal(goalVerifyWorkflow.nextIntent.targetRuntimeStage, 'execute');
323
+ assert.equal(goalVerifyWorkflow.nextIntent.displayCommand, '/sdd:execute close --branch feature --compact-json');
324
+ assert.equal(goalVerifyWorkflow.nextIntent.canonicalCommand, 'sdd execute close --branch feature --compact-json');
325
+ assert.equal(goalVerifyWorkflow.nextIntent.canonicalCommand.includes('sync-back'), false);
326
+ } finally {
327
+ await rm(root, { recursive: true, force: true });
328
+ }
329
+ });
330
+
331
+ test('workflow state routes stale aligned truthAlignment refs to minimal document reconciliation', async () => {
332
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-stale-truth-'));
333
+ try {
334
+ await initProject(root);
335
+ await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
336
+ const specPath = path.join(root, 'specs', 'feature', 'spec.md');
337
+ const tasksPath = path.join(root, 'specs', 'feature', 'tasks.md');
338
+ const specHash = hashTestDocument(await readFile(specPath, 'utf8'));
339
+ const tasksHash = hashTestDocument(await readFile(tasksPath, 'utf8'));
340
+ await recordTruthAlignmentProjection(root, {
341
+ contract: 'sdd-truth-alignment-v1',
342
+ branch: 'feature',
343
+ sourceStage: 'execute',
344
+ declaredTruthRefs: [
345
+ { kind: 'document', ref: 'specs/feature/spec.md', hash: specHash },
346
+ { kind: 'document', ref: 'specs/feature/tasks.md', hash: tasksHash }
347
+ ],
348
+ acceptedRealityRefs: [{ kind: 'artifact', ref: '.sdd/runs/feature/execute/evidence-judgment-v1.md' }],
349
+ status: 'aligned',
350
+ ownerStage: null,
351
+ semanticImpact: 'none',
352
+ staleRefs: [],
353
+ invalidatesStages: [],
354
+ reasons: ['Accepted execute evidence judgment is structurally aligned with declared upstream truth refs.'],
355
+ createdAt: '2026-06-01T00:00:00.000Z'
356
+ });
357
+ await writeFile(tasksPath, `${await readFile(tasksPath, 'utf8')}\nAdditional documentation-only acceptance clarification.\n`, 'utf8');
358
+
359
+ const workflow = await resolveWorkflowState(root, { branch: 'feature' });
360
+
361
+ assert.equal(workflow.nextIntent.intent, 'reconcile_truth');
362
+ assert.equal(workflow.nextIntent.bundle, 'tasks');
363
+ assert.equal(workflow.nextIntent.targetRuntimeStage, 'tasks');
364
+ assert.equal(workflow.recommendedNextCommand, 'sdd tasks close --branch feature --compact-json');
365
+ assert.equal(workflow.truthReconciliation?.changeKind, 'documentation_catchup');
366
+ assert.equal(workflow.truthReconciliation?.semanticImpact, 'none');
367
+ assert.deepEqual(workflow.truthReconciliation?.minimalFrontier, ['tasks']);
368
+ assert.equal(workflow.truthReconciliation?.changedRef.ref, 'specs/feature/tasks.md');
369
+ assert.equal(workflow.truthReconciliation?.oldHash, tasksHash);
370
+ assert.notEqual(workflow.truthReconciliation?.newHash, tasksHash);
371
+ assert.equal(workflow.nextIntent.canonicalCommand.includes('sync-back'), false);
372
+ } finally {
373
+ await rm(root, { recursive: true, force: true });
374
+ }
375
+ });
376
+
377
+ test('workflow state skips document truth refs already accepted by stage close', async () => {
378
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-stale-truth-close-'));
379
+ try {
380
+ await initProject(root);
381
+ await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
382
+ const specPath = path.join(root, 'specs', 'feature', 'spec.md');
383
+ const tasksPath = path.join(root, 'specs', 'feature', 'tasks.md');
384
+ const originalSpecHash = hashTestDocument(await readFile(specPath, 'utf8'));
385
+ const originalTasksHash = hashTestDocument(await readFile(tasksPath, 'utf8'));
386
+ await recordTruthAlignmentProjection(root, {
387
+ contract: 'sdd-truth-alignment-v1',
388
+ branch: 'feature',
389
+ sourceStage: 'execute',
390
+ declaredTruthRefs: [
391
+ { kind: 'document', ref: 'specs/feature/spec.md', hash: originalSpecHash },
392
+ { kind: 'document', ref: 'specs/feature/tasks.md', hash: originalTasksHash }
393
+ ],
394
+ acceptedRealityRefs: [{ kind: 'artifact', ref: '.sdd/runs/feature/execute/evidence-judgment-v1.md' }],
395
+ status: 'aligned',
396
+ ownerStage: null,
397
+ semanticImpact: 'none',
398
+ staleRefs: [],
399
+ invalidatesStages: [],
400
+ reasons: ['Accepted execute evidence judgment is structurally aligned with declared upstream truth refs.'],
401
+ createdAt: '2026-06-01T00:00:00.000Z'
402
+ });
403
+ await writeFile(specPath, `${await readFile(specPath, 'utf8')}\nSpec documentation-only correction.\n`, 'utf8');
404
+ await writeFile(tasksPath, `${await readFile(tasksPath, 'utf8')}\nTasks documentation-only correction.\n`, 'utf8');
405
+ const currentSpecHash = hashTestDocument(await readFile(specPath, 'utf8'));
406
+ const currentTasksHash = hashTestDocument(await readFile(tasksPath, 'utf8'));
407
+ const acceptedSpecRef = { kind: 'document' as const, ref: 'specs/feature/spec.md', hash: currentSpecHash };
408
+ const generatedAt = '2026-06-01T00:00:02.000Z';
409
+ await recordRuntimeProjectionEnvelope(root, {
410
+ projectionType: SPEC_COLLABORATION_ADJUDICATION_PROJECTION_TYPE,
411
+ scopeKey: specCollaborationScopeKey({ branch: 'feature' }),
412
+ inputHash: 'spec-adjudication-v2',
413
+ producer: 'phase9.1-spec-stage-collaboration-runtime',
414
+ producerVersion: 'phase9.1-spec-stage-collaboration-runtime-v1',
415
+ generatedAt,
416
+ payload: {
417
+ contract: 'phase-9.1-stage-collaboration-runtime-v1',
418
+ adjudicationId: 'spec-adjudication-v2',
419
+ stage: 'spec',
420
+ scope: { branch: 'feature' },
421
+ health: 'ready_for_plan',
422
+ stageDecision: {
423
+ contract: 'phase-9.1-stage-collaboration-runtime-v1',
424
+ decisionId: 'spec-stage-decision-v2',
425
+ stage: 'spec',
426
+ scope: { branch: 'feature' },
427
+ status: 'completed',
428
+ health: 'ready_for_plan',
429
+ acceptedDecisionRefs: [acceptedSpecRef],
430
+ advisoryRefs: [],
431
+ capabilityRefs: [],
432
+ blockingReasons: [],
433
+ createdAt: generatedAt
434
+ },
435
+ handoffPacket: null,
436
+ rejection: null,
437
+ nextActions: [],
438
+ closureRefs: {
439
+ acceptedSpecRef,
440
+ specHash: currentSpecHash,
441
+ reasons: []
442
+ },
443
+ createdAt: generatedAt
444
+ }
445
+ });
446
+
447
+ const workflow = await resolveWorkflowState(root, { branch: 'feature' });
448
+
449
+ assert.equal(workflow.nextIntent.intent, 'reconcile_truth');
450
+ assert.equal(workflow.nextIntent.bundle, 'tasks');
451
+ assert.equal(workflow.nextIntent.targetRuntimeStage, 'tasks');
452
+ assert.equal(workflow.recommendedNextCommand, 'sdd tasks close --branch feature --compact-json');
453
+ assert.equal(workflow.truthReconciliation?.changedRef.ref, 'specs/feature/tasks.md');
454
+ assert.equal(workflow.truthReconciliation?.oldHash, originalTasksHash);
455
+ assert.equal(workflow.truthReconciliation?.newHash, currentTasksHash);
456
+ assert.equal(workflow.truthReconciliation?.reasons.some((reason) => reason.includes('specs/feature/spec.md')), false);
457
+ } finally {
458
+ await rm(root, { recursive: true, force: true });
459
+ }
460
+ });
461
+
462
+ test('workflow state routes open repairs before repeating do or validation', async () => {
463
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-repair-'));
464
+ try {
465
+ await initProject(root);
466
+ await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
467
+ await recordRuntimeRepair(root, buildOpenRepairRecord({
468
+ branchSlug: 'feature',
469
+ taskId: 'T1',
470
+ message: 'validation command is not directly executable: manual: inspect service',
471
+ recommendedCommands: ['sdd doctor --branch feature --latest-only']
472
+ }));
473
+
474
+ const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
475
+
476
+ assert.equal(workflow.openRepairs.length, 1);
477
+ assert.equal(workflow.nextIntent.intent, 'repair_failure');
478
+ assert.equal(workflow.recommendedNextCommand, 'sdd doctor --branch feature --latest-only');
479
+ assert.equal(workflow.blockingReasons.some((reason) => reason.includes('not directly executable')), true);
480
+ } finally {
481
+ await rm(root, { recursive: true, force: true });
482
+ }
483
+ });
484
+
485
+ test('workflow state strict stale rejection names tasks contract drift', async () => {
486
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-stale-dimension-'));
487
+ try {
488
+ await initProject(root);
489
+ const originalTasks = validTaskMarkdown('T1', []);
490
+ await writeBranchDocs(root, 'feature', originalTasks);
491
+ const run = await createRun(root, { runId: 'run-stale-contract' });
492
+ await bindTestRunState(root, run.runId, 'feature', 'T1');
493
+ await markTestRunReadyForShip(root, run.runId, 'T1');
494
+ await writeBranchDocs(root, 'feature', originalTasks.replace('risk: []', 'required_artifacts:\n - artifacts/implement-T1.md\nrisk: []'));
495
+
496
+ const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
497
+ const rejected = workflow.latestEligibleRunsByTask.find((selection) => selection.taskId === 'T1')?.rejected.find((candidate) => candidate.runId === 'run-stale-contract');
498
+
499
+ assert.equal(workflow.latestRun, null);
500
+ assert.equal(rejected?.compatibility, 'strict_stale');
501
+ assert.equal(rejected?.reasons.some((reason) => reason.includes('tasks contract hash drift')), true);
502
+ } finally {
503
+ await rm(root, { recursive: true, force: true });
504
+ }
505
+ });
506
+
507
+
508
+ test('workflow state does not route to ship until every required task has PASS evidence', async () => {
509
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-readiness-'));
510
+ try {
511
+ await initProject(root);
512
+ await writeBranchDocs(root, 'feature', `# Tasks\n\n${validTaskMarkdown('T1', []).replace('packages/core/src/index.ts', 'docs/t1.md')}\n${validTaskMarkdown('T2', []).replace('T1', 'T2').replace('packages/core/src/index.ts', 'docs/t2.md')}`);
513
+ const run = await createRun(root, { runId: 'run-t1-pass' });
514
+ await bindTestRunState(root, run.runId, 'feature', 'T1');
515
+ await markTestRunReadyForShip(root, run.runId, 'T1');
516
+
517
+ const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
518
+
519
+ assert.equal(workflow.nextIntent.stage, 'execute');
520
+ assert.equal(workflow.recommendedNextCommand, 'sdd execute --branch feature');
521
+ assert.deepEqual(workflow.workflowReadiness.requiredTaskIds, ['T1', 'T2']);
522
+ assert.deepEqual(workflow.workflowReadiness.acceptedTaskIds, ['T1']);
523
+ assert.deepEqual(workflow.workflowReadiness.missingTaskIds, ['T2']);
524
+ assert.equal(workflow.workflowReadiness.readyForShip, false);
525
+ assert.deepEqual(workflow.whyNotShip, ['Task T2 has no accepted validation PASS evidence.']);
526
+ } finally {
527
+ await rm(root, { recursive: true, force: true });
528
+ }
529
+ });
530
+
531
+ test('workflow state resolver reports affected-file conflicts without run-index rebuild', async () => {
532
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-conflict-'));
533
+ try {
534
+ await initProject(root);
535
+ await writeBranchDocs(root, 'feature', `${validTaskMarkdown('T1', []).replace('packages/core/src/index.ts', 'src/shared.ts')}\n${validTaskMarkdown('T2', []).replace('T1', 'T2').replace('packages/core/src/index.ts', 'src/shared.ts')}`);
536
+ const runA = await createRun(root, { runId: 'run-a' });
537
+ await bindTestRunState(root, runA.runId, 'feature', 'T1');
538
+ await markTestRunReadyForShip(root, runA.runId, 'T1');
539
+ const runB = await createRun(root, { runId: 'run-b' });
540
+ await bindTestRunState(root, runB.runId, 'feature', 'T2');
541
+ const archived = await createRun(root, { runId: 'run-c' });
542
+ await writeRunState(root, { ...archived, status: 'archived' });
543
+
544
+ const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
545
+
546
+ assert.deepEqual(workflow.affectedFileConflicts.map((entry) => entry.runId), ['run-b']);
547
+ assert.equal(workflow.blockingReasons.some((reason) => reason.includes('src/shared.ts')), true);
548
+ } finally {
549
+ await rm(root, { recursive: true, force: true });
550
+ }
551
+ });
552
+
553
+ test('workflow state ignores superseded failed and foreground observer conflict candidates', async () => {
554
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-filtered-conflicts-'));
555
+ try {
556
+ await initProject(root);
557
+ await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []).replace('packages/core/src/index.ts', 'docs/t1.md'));
558
+ const failed = await createRun(root, { runId: 'run-failed' });
559
+ await bindTestRunState(root, failed.runId, 'feature', 'T1');
560
+ await writeRunState(root, {
561
+ ...await readRunState(root, failed.runId),
562
+ status: 'failed',
563
+ validation: { status: 'fail', commands: ['npm test'], evidence: [] }
564
+ });
565
+ const observer = await createRun(root, { runId: 'run-observer' });
566
+ await bindTestRunState(root, observer.runId, 'feature', 'T1');
567
+ const delegation = createDelegationRecord({
568
+ delegationId: 'F-T1-observer-001',
569
+ task: 'T1',
570
+ agent: 'observer',
571
+ runMode: 'foreground',
572
+ blocking: false,
573
+ requiredForPhaseExit: false,
574
+ expectedArtifact: 'artifacts/observer-T1.md'
575
+ });
576
+ await writeRunState(root, {
577
+ ...await readRunState(root, observer.runId),
578
+ status: 'completed',
579
+ phase: 'foreground-subagents',
580
+ delegations: { [delegation.delegationId]: { ...delegation, status: 'COMPLETED', terminalEventAt: new Date().toISOString() } }
581
+ });
582
+ const retry = await createRun(root, { runId: 'run-retry' });
583
+ await bindTestRunState(root, retry.runId, 'feature', 'T1');
584
+ await markTestRunReadyForShip(root, retry.runId, 'T1');
585
+
586
+ const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
587
+
588
+ assert.equal(workflow.latestRun?.runId, 'run-retry');
589
+ assert.deepEqual(workflow.affectedFileConflicts, []);
590
+ assert.equal(workflow.blockingReasons.some((reason) => reason.includes('Affected file')), false);
591
+ } finally {
592
+ await rm(root, { recursive: true, force: true });
593
+ }
594
+ });
595
+
596
+ test('workflow state resolver surfaces dependency blockers and points next action upstream', async () => {
597
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-dependencies-'));
598
+ try {
599
+ await initProject(root);
600
+ await writeBranchDocs(root, 'feature', `# Tasks\n\n${validTaskMarkdown('DEP1', [])}\n${validTaskMarkdown('DEP2', ['DEP1']).replace('packages/core/src/index.ts', 'docs/dep2.md')}`);
601
+
602
+ const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'DEP2' });
603
+
604
+ assert.deepEqual(workflow.dependencyBlockers.map((blocker) => `${blocker.taskId}->${blocker.dependencyId}`), ['DEP2->DEP1']);
605
+ assert.equal(workflow.blockingReasons.some((reason) => reason.includes('DEP2 depends on DEP1')), true);
606
+ assert.equal(workflow.recommendedNextCommand, 'sdd execute --branch feature');
607
+ } finally {
608
+ await rm(root, { recursive: true, force: true });
609
+ }
610
+ });
611
+
612
+ test('workflow state treats implemented batch dependency as ready for downstream do', async () => {
613
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-runtime-dependency-ready-'));
614
+ try {
615
+ await initProject(root);
616
+ await writeBranchDocs(root, 'feature', `# Tasks
617
+
618
+ ${validTaskMarkdown('DEP1', [])
619
+ .replace('packages/core/src/index.ts', 'docs/dep1.md')
620
+ .replace('validation:\n - npm test', 'validation_batch: dep-batch\nvalidation_timing: batch_end\nrequires_verify_before_next: false\nvalidation:\n - npm test')}
621
+ ${validTaskMarkdown('DEP2', ['DEP1'])
622
+ .replace('packages/core/src/index.ts', 'docs/dep2.md')
623
+ .replace('validation:\n - npm test', 'validation_batch: dep-batch\nvalidation_timing: batch_end\nrequires_verify_before_next: false\nvalidation:\n - npm test')}`);
624
+ const run = await createRun(root, { runId: 'run-dep1-implemented' });
625
+ await bindTestRunState(root, run.runId, 'feature', 'DEP1');
626
+ const bound = await readRunState(root, run.runId);
627
+ await writeRunState(root, {
628
+ ...bound,
629
+ status: 'completed',
630
+ tasks: {
631
+ ...bound.tasks,
632
+ DEP1: {
633
+ status: 'implemented_pending_validation',
634
+ implementationStatus: 'implemented',
635
+ verificationStatus: 'pending_batch',
636
+ validationBatch: 'dep-batch',
637
+ validationTiming: 'batch_end',
638
+ requiresVerifyBeforeNext: false,
639
+ gaps: [],
640
+ artifacts: []
641
+ }
642
+ }
643
+ });
644
+
645
+ const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'DEP2' });
646
+
647
+ assert.deepEqual(workflow.dependencyBlockers, []);
648
+ assert.equal(workflow.recommendedNextCommand, 'sdd execute --branch feature');
649
+ } finally {
650
+ await rm(root, { recursive: true, force: true });
651
+ }
652
+ });
653
+
654
+ test('workflow state blocks downstream do until strict dependency verification passes', async () => {
655
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-runtime-dependency-strict-'));
656
+ try {
657
+ await initProject(root);
658
+ await writeBranchDocs(root, 'feature', `# Tasks
659
+
660
+ ${validTaskMarkdown('DEP1', [])
661
+ .replace('packages/core/src/index.ts', 'docs/dep1.md')
662
+ .replace('validation:\n - npm test', 'validation_timing: task_end\nrequires_verify_before_next: true\nvalidation:\n - npm test')}
663
+ ${validTaskMarkdown('DEP2', ['DEP1']).replace('packages/core/src/index.ts', 'docs/dep2.md')}`);
664
+ const run = await createRun(root, { runId: 'run-dep1-strict-implemented' });
665
+ await bindTestRunState(root, run.runId, 'feature', 'DEP1');
666
+ const bound = await readRunState(root, run.runId);
667
+ await writeRunState(root, {
668
+ ...bound,
669
+ status: 'completed',
670
+ tasks: {
671
+ ...bound.tasks,
672
+ DEP1: {
673
+ status: 'implemented_pending_validation',
674
+ implementationStatus: 'implemented',
675
+ verificationStatus: 'not_run',
676
+ validationBatch: null,
677
+ validationTiming: 'task_end',
678
+ requiresVerifyBeforeNext: true,
679
+ gaps: [],
680
+ artifacts: []
681
+ }
682
+ }
683
+ });
684
+
685
+ const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'DEP2' });
686
+
687
+ assert.deepEqual(workflow.dependencyBlockers.map((blocker) => `${blocker.taskId}->${blocker.dependencyId}`), ['DEP2->DEP1']);
688
+ assert.equal(workflow.blockingReasons.some((reason) => reason.includes('has not passed required verification')), true);
689
+ assert.equal(workflow.recommendedNextCommand, 'sdd execute --branch feature --json');
690
+ } finally {
691
+ await rm(root, { recursive: true, force: true });
692
+ }
693
+ });
694
+
695
+
696
+ test('latest eligible selector prefers older compatible evidence over newer strict-stale evidence', async () => {
697
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-eligible-'));
698
+ try {
699
+ await initProject(root);
700
+ await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
701
+ const compatible = await createRun(root, { runId: 'run-compatible' });
702
+ await bindTestRunState(root, compatible.runId, 'feature', 'T1');
703
+ await markTestRunReadyForShip(root, compatible.runId, 'T1');
704
+
705
+ const strictStale = await createRun(root, { runId: 'run-strict-stale' });
706
+ await bindTestRunState(root, strictStale.runId, 'feature', 'T1');
707
+ await markTestRunReadyForShip(root, strictStale.runId, 'T1');
708
+ const strictStaleState = await readRunState(root, strictStale.runId);
709
+ await writeRunState(root, {
710
+ ...strictStaleState,
711
+ documentSnapshot: {
712
+ ...strictStaleState.documentSnapshot,
713
+ tasksContractHash: 'stale-tasks-contract-hash',
714
+ taskContractHash: 'stale-task-contract-hash',
715
+ }
716
+ });
717
+
718
+ const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
719
+ const selection = workflow.latestEligibleRunsByTask.find((entry) => entry.taskId === 'T1');
720
+
721
+ assert.equal(workflow.latestRun?.runId, 'run-compatible');
722
+ assert.equal(selection?.selected?.runId, 'run-compatible');
723
+ assert.deepEqual(selection?.rejected.map((entry) => `${entry.runId}:${entry.compatibility}`), ['run-strict-stale:strict_stale']);
724
+ assert.equal(selection?.rejected[0]?.reasons.some((reason) => reason.includes('strict_stale')), true);
725
+ } finally {
726
+ await rm(root, { recursive: true, force: true });
727
+ }
728
+ });
729
+
730
+ test.skip('latest eligible selector keeps task-local evidence when another task changes', async () => {
731
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-task-local-eligible-'));
732
+ try {
733
+ await initProject(root);
734
+ const task1 = validTaskMarkdown('T1', []).replace('packages/core/src/index.ts', 'docs/t1.md');
735
+ const task2 = validTaskMarkdown('T2', []).replace('T1', 'T2').replace('packages/core/src/index.ts', 'docs/t2.md');
736
+ await writeBranchDocs(root, 'feature', `# Tasks\n\n${task1}\n${task2}`);
737
+ const run = await createRun(root, { runId: 'run-t1-compatible' });
738
+ await bindTestRunState(root, run.runId, 'feature', 'T1');
739
+ await markTestRunReadyForShip(root, run.runId, 'T1');
740
+ await writeBranchDocs(root, 'feature', `# Tasks\n\n${task1}\n${task2.replace('risk: []', 'risk:\n - security')}`);
741
+
742
+ const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
743
+ const selection = workflow.latestEligibleRunsByTask.find((entry) => entry.taskId === 'T1');
744
+
745
+ assert.equal(workflow.latestRun?.runId, 'run-t1-compatible');
746
+ assert.equal(selection?.selected?.runId, 'run-t1-compatible');
747
+ assert.deepEqual(selection?.rejected.map((entry) => entry.runId), []);
748
+ } finally {
749
+ await rm(root, { recursive: true, force: true });
750
+ }
751
+ });
752
+
753
+ test('latest eligible selector rejects newer blocked runs and keeps older completed evidence eligible', async () => {
754
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-blocked-eligible-'));
755
+ try {
756
+ await initProject(root);
757
+ await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
758
+ const completed = await createRun(root, { runId: 'run-completed' });
759
+ await bindTestRunState(root, completed.runId, 'feature', 'T1');
760
+ await markTestRunReadyForShip(root, completed.runId, 'T1');
761
+
762
+ const blocked = await createRun(root, { runId: 'run-blocked' });
763
+ await bindTestRunState(root, blocked.runId, 'feature', 'T1');
764
+ await markTestRunReadyForShip(root, blocked.runId, 'T1');
765
+ await writeRunState(root, { ...await readRunState(root, blocked.runId), status: 'blocked' });
766
+
767
+ const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
768
+ const selection = workflow.latestEligibleRunsByTask.find((entry) => entry.taskId === 'T1');
769
+
770
+ assert.equal(selection?.selected?.runId, 'run-completed');
771
+ assert.equal(selection?.rejected.some((entry) => entry.runId === 'run-blocked' && entry.reasons.includes('Run is blocked.')), true);
772
+ } finally {
773
+ await rm(root, { recursive: true, force: true });
774
+ }
775
+ });
776
+
777
+ test('latest eligible selector returns visible candidates and rejects archived or failed runs with reasons', async () => {
778
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-rejected-'));
779
+ try {
780
+ await initProject(root);
781
+ await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
782
+ const failed = await createRun(root, { runId: 'run-failed' });
783
+ await bindTestRunState(root, failed.runId, 'feature', 'T1');
784
+ await writeRunState(root, {
785
+ ...await readRunState(root, failed.runId),
786
+ status: 'failed',
787
+ validation: { status: 'fail', commands: ['npm test'], evidence: [] }
788
+ });
789
+ const archived = await createRun(root, { runId: 'run-archived' });
790
+ await bindTestRunState(root, archived.runId, 'feature', 'T1');
791
+ await writeRunState(root, { ...await readRunState(root, archived.runId), status: 'archived' });
792
+
793
+ const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
794
+ const selection = workflow.latestEligibleRunsByTask.find((entry) => entry.taskId === 'T1');
795
+
796
+ assert.equal(workflow.latestRun, null);
797
+ assert.deepEqual(selection?.candidates.map((entry) => entry.runId), ['run-failed']);
798
+ assert.deepEqual(selection?.rejected.map((entry) => entry.runId).sort(), ['run-archived', 'run-failed']);
799
+ assert.equal(selection?.rejected.some((entry) => entry.reasons.includes('Run failed.')), true);
800
+ assert.equal(selection?.rejected.some((entry) => entry.reasons.includes('Run is archived.')), true);
801
+ } finally {
802
+ await rm(root, { recursive: true, force: true });
803
+ }
804
+ });
805
+
806
+ test('workflow state uses explicit partition runtime despite divergent git branch', async () => {
807
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-divergent-'));
808
+ try {
809
+ await initProject(root);
810
+ await execFileAsync('git', ['init'], { cwd: root });
811
+ await execFileAsync('git', ['checkout', '-b', 'current-branch'], { cwd: root });
812
+ await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', [])
813
+ .replace('packages/core/src/index.ts', 'docs/t1.md')
814
+ .replace('validation:\n - npm test', 'validation_timing: task_end\nrequires_verify_before_next: true\nvalidation:\n - npm test'));
815
+ const divergent = await createRun(root, { runId: 'run-divergent' });
816
+ await bindTestRunState(root, divergent.runId, 'feature', 'T1');
817
+ const bound = await readRunState(root, divergent.runId);
818
+ await writeRunState(root, {
819
+ ...bound,
820
+ status: 'completed',
821
+ tasks: {
822
+ ...bound.tasks,
823
+ T1: {
824
+ status: 'implemented_pending_validation',
825
+ implementationStatus: 'implemented',
826
+ verificationStatus: 'not_run',
827
+ validationBatch: null,
828
+ validationTiming: 'task_end',
829
+ requiresVerifyBeforeNext: true,
830
+ gaps: [],
831
+ artifacts: []
832
+ }
833
+ }
834
+ });
835
+
836
+ const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
837
+ const selection = workflow.latestEligibleRunsByTask.find((entry) => entry.taskId === 'T1');
838
+
839
+ assert.equal(workflow.latestRun?.runId, 'run-divergent');
840
+ assert.equal(selection?.selected?.runId, 'run-divergent');
841
+ assert.deepEqual(selection?.rejected.map((entry) => entry.runId), []);
842
+ assert.equal(workflow.nextIntent.intent, 'run_task_validation');
843
+ assert.equal(workflow.recommendedNextCommand, 'sdd execute --branch feature --json');
844
+ } finally {
845
+ await rm(root, { recursive: true, force: true });
846
+ }
847
+ });
848
+
849
+ test('workflow state recommends wave validation for implemented wave_end boundary', async () => {
850
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-wave-boundary-'));
851
+ try {
852
+ await initProject(root);
853
+ await writeBranchDocs(root, 'feature', `# Tasks
854
+
855
+ ${validTaskMarkdown('W1', [])
856
+ .replace('packages/core/src/index.ts', 'docs/w1.md')
857
+ .replace('validation:\n - npm test', 'validation_batch: docs-wave\nvalidation_timing: wave_end\nrequires_verify_before_next: false\nvalidation:\n - npm test')}`);
858
+ const run = await createRun(root, { runId: 'run-w1-implemented' });
859
+ await bindTestRunState(root, run.runId, 'feature', 'W1');
860
+ const bound = await readRunState(root, run.runId);
861
+ await writeRunState(root, {
862
+ ...bound,
863
+ status: 'completed',
864
+ tasks: {
865
+ ...bound.tasks,
866
+ W1: {
867
+ status: 'implemented_pending_validation',
868
+ implementationStatus: 'implemented',
869
+ verificationStatus: 'pending_batch',
870
+ validationBatch: 'docs-wave',
871
+ validationTiming: 'wave_end',
872
+ requiresVerifyBeforeNext: false,
873
+ gaps: [],
874
+ artifacts: []
875
+ }
876
+ }
877
+ });
878
+
879
+ const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'W1' });
880
+
881
+ assert.equal(workflow.nextIntent.intent, 'run_wave_validation');
882
+ assert.equal(workflow.recommendedNextCommand, 'sdd execute --branch feature --json');
883
+ } finally {
884
+ await rm(root, { recursive: true, force: true });
885
+ }
886
+ });
887
+
888
+ test('workflow state dependency readiness ignores newer ineligible runtime state', async () => {
889
+ const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-eligible-runtime-'));
890
+ try {
891
+ await initProject(root);
892
+ await writeBranchDocs(root, 'feature', `# Tasks
893
+
894
+ ${validTaskMarkdown('DEP1', [])
895
+ .replace('packages/core/src/index.ts', 'docs/dep1.md')
896
+ .replace('validation:\n - npm test', 'validation_batch: dep-batch\nvalidation_timing: batch_end\nrequires_verify_before_next: false\nvalidation:\n - npm test')}
897
+ ${validTaskMarkdown('DEP2', ['DEP1']).replace('packages/core/src/index.ts', 'docs/dep2.md')}`);
898
+ const eligible = await createRun(root, { runId: 'run-dep1-eligible' });
899
+ await bindTestRunState(root, eligible.runId, 'feature', 'DEP1');
900
+ const eligibleState = await readRunState(root, eligible.runId);
901
+ await writeRunState(root, {
902
+ ...eligibleState,
903
+ status: 'completed',
904
+ tasks: {
905
+ ...eligibleState.tasks,
906
+ DEP1: {
907
+ status: 'implemented_pending_validation',
908
+ implementationStatus: 'implemented',
909
+ verificationStatus: 'pending_batch',
910
+ validationBatch: 'dep-batch',
911
+ validationTiming: 'batch_end',
912
+ requiresVerifyBeforeNext: false,
913
+ gaps: [],
914
+ artifacts: []
915
+ }
916
+ }
917
+ });
918
+ const blocked = await createRun(root, { runId: 'run-dep1-blocked-newer' });
919
+ await bindTestRunState(root, blocked.runId, 'feature', 'DEP1');
920
+ const blockedState = await readRunState(root, blocked.runId);
921
+ await writeRunState(root, {
922
+ ...blockedState,
923
+ status: 'blocked',
924
+ updatedAt: new Date(Date.parse(eligibleState.updatedAt) + 1000).toISOString(),
925
+ tasks: {
926
+ ...blockedState.tasks,
927
+ DEP1: {
928
+ status: 'pending',
929
+ implementationStatus: 'not_started',
930
+ verificationStatus: 'not_run',
931
+ validationBatch: 'dep-batch',
932
+ validationTiming: 'batch_end',
933
+ requiresVerifyBeforeNext: false,
934
+ gaps: [],
935
+ artifacts: []
936
+ }
937
+ }
938
+ });
939
+
940
+ const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'DEP2' });
941
+
942
+ assert.deepEqual(workflow.dependencyBlockers, []);
943
+ assert.equal(workflow.recommendedNextCommand, 'sdd execute --branch feature --json');
944
+ } finally {
945
+ await rm(root, { recursive: true, force: true });
946
+ }
947
+ });
948
+
949
+ function truthAlignmentProjection(input: Pick<TruthAlignmentProjection, 'branch' | 'status' | 'ownerStage' | 'semanticImpact' | 'invalidatesStages' | 'staleRefs' | 'reasons'> & { createdAt?: string }): TruthAlignmentProjection {
950
+ return {
951
+ contract: 'sdd-truth-alignment-v1',
952
+ branch: input.branch,
953
+ sourceStage: 'execute',
954
+ declaredTruthRefs: [
955
+ { kind: 'document', ref: `specs/${input.branch}/spec.md`, hash: 'spec-hash' },
956
+ { kind: 'document', ref: `specs/${input.branch}/tasks.md`, hash: 'tasks-hash' }
957
+ ],
958
+ acceptedRealityRefs: [
959
+ { kind: 'artifact', ref: `.sdd/runs/${input.branch}/execute/evidence-judgment-v1.md`, hash: 'goal-hash' },
960
+ { kind: 'artifact', ref: `.sdd/runs/${input.branch}/execute/implementation-v1.md`, hash: 'implementation-hash' }
961
+ ],
962
+ status: input.status,
963
+ ownerStage: input.ownerStage,
964
+ semanticImpact: input.semanticImpact,
965
+ staleRefs: input.staleRefs,
966
+ invalidatesStages: input.invalidatesStages,
967
+ reasons: input.reasons,
968
+ createdAt: input.createdAt ?? '2026-06-01T00:00:00.000Z'
969
+ };
957
970
  }