sdd-agent-platform 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (698) hide show
  1. package/README.md +24 -28
  2. package/node_modules/@sdd-agent-platform/core/dist/ai-tools.js +84 -103
  3. package/node_modules/@sdd-agent-platform/core/dist/ai-tools.js.map +1 -1
  4. package/node_modules/@sdd-agent-platform/core/dist/config/init-project.d.ts +10 -6
  5. package/node_modules/@sdd-agent-platform/core/dist/config/init-project.js +7 -8
  6. package/node_modules/@sdd-agent-platform/core/dist/config/init-project.js.map +1 -1
  7. package/node_modules/@sdd-agent-platform/core/dist/config/project-config.d.ts +3 -1
  8. package/node_modules/@sdd-agent-platform/core/dist/config/project-config.js +7 -3
  9. package/node_modules/@sdd-agent-platform/core/dist/config/project-config.js.map +1 -1
  10. package/node_modules/@sdd-agent-platform/core/dist/config/starter-documents.d.ts +0 -1
  11. package/node_modules/@sdd-agent-platform/core/dist/config/starter-documents.js +374 -421
  12. package/node_modules/@sdd-agent-platform/core/dist/config/starter-documents.js.map +1 -1
  13. package/node_modules/@sdd-agent-platform/core/dist/context/build-package.d.ts +1 -1
  14. package/node_modules/@sdd-agent-platform/core/dist/context/build-package.js +7 -19
  15. package/node_modules/@sdd-agent-platform/core/dist/context/build-package.js.map +1 -1
  16. package/node_modules/@sdd-agent-platform/core/dist/contracts.d.ts +7 -1
  17. package/node_modules/@sdd-agent-platform/core/dist/contracts.js +6 -0
  18. package/node_modules/@sdd-agent-platform/core/dist/contracts.js.map +1 -1
  19. package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/document-chain.js +2 -12
  20. package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/document-chain.js.map +1 -1
  21. package/node_modules/@sdd-agent-platform/core/dist/doctor/doctor.js +1 -18
  22. package/node_modules/@sdd-agent-platform/core/dist/doctor/doctor.js.map +1 -1
  23. package/node_modules/@sdd-agent-platform/core/dist/evidence/lookup.d.ts +1 -1
  24. package/node_modules/@sdd-agent-platform/core/dist/evidence/lookup.js +1 -1
  25. package/node_modules/@sdd-agent-platform/core/dist/evidence/lookup.js.map +1 -1
  26. package/node_modules/@sdd-agent-platform/core/dist/evidence-runtime/contracts.d.ts +0 -1
  27. package/node_modules/@sdd-agent-platform/core/dist/evidence-runtime/coordination.js +110 -0
  28. package/node_modules/@sdd-agent-platform/core/dist/evidence-runtime/coordination.js.map +1 -0
  29. package/node_modules/@sdd-agent-platform/core/dist/execution/host-invocation.js +83 -83
  30. package/node_modules/@sdd-agent-platform/core/dist/instructions.d.ts +1 -1
  31. package/node_modules/@sdd-agent-platform/core/dist/instructions.js +37 -80
  32. package/node_modules/@sdd-agent-platform/core/dist/instructions.js.map +1 -1
  33. package/node_modules/@sdd-agent-platform/core/dist/lifecycle/ship.js +58 -68
  34. package/node_modules/@sdd-agent-platform/core/dist/lifecycle/ship.js.map +1 -1
  35. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/contracts.d.ts +159 -0
  36. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/contracts.js +7 -0
  37. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/contracts.js.map +1 -0
  38. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/kernel.d.ts +16 -0
  39. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/kernel.js +461 -0
  40. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/kernel.js.map +1 -0
  41. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph.d.ts +2 -0
  42. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph.js +3 -0
  43. package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph.js.map +1 -0
  44. package/node_modules/@sdd-agent-platform/core/dist/orchestration/contracts.d.ts +1 -1
  45. package/node_modules/@sdd-agent-platform/core/dist/orchestration/runtime.js +21 -28
  46. package/node_modules/@sdd-agent-platform/core/dist/orchestration/runtime.js.map +1 -1
  47. package/node_modules/@sdd-agent-platform/core/dist/registries/agent-registry.js +124 -40
  48. package/node_modules/@sdd-agent-platform/core/dist/registries/agent-registry.js.map +1 -1
  49. package/node_modules/@sdd-agent-platform/core/dist/registries/command-team-runtime.d.ts +1 -1
  50. package/node_modules/@sdd-agent-platform/core/dist/registries/command-team-runtime.js +6 -13
  51. package/node_modules/@sdd-agent-platform/core/dist/registries/command-team-runtime.js.map +1 -1
  52. package/node_modules/@sdd-agent-platform/core/dist/registries/plan-scout-domains.d.ts +13 -0
  53. package/node_modules/@sdd-agent-platform/core/dist/registries/plan-scout-domains.js +76 -0
  54. package/node_modules/@sdd-agent-platform/core/dist/registries/plan-scout-domains.js.map +1 -0
  55. package/node_modules/@sdd-agent-platform/core/dist/registries/skill-capabilities.js +7 -7
  56. package/node_modules/@sdd-agent-platform/core/dist/registries/skill-capabilities.js.map +1 -1
  57. package/node_modules/@sdd-agent-platform/core/dist/registries/tool-capabilities.js +6 -6
  58. package/node_modules/@sdd-agent-platform/core/dist/registries/tool-capabilities.js.map +1 -1
  59. package/node_modules/@sdd-agent-platform/core/dist/registries/workflow-gates.d.ts +1 -1
  60. package/node_modules/@sdd-agent-platform/core/dist/registries/workflow-gates.js +18 -18
  61. package/node_modules/@sdd-agent-platform/core/dist/registries/workflow-gates.js.map +1 -1
  62. package/node_modules/@sdd-agent-platform/core/dist/risk/consumer-diagnostics.js +2 -1
  63. package/node_modules/@sdd-agent-platform/core/dist/risk/consumer-diagnostics.js.map +1 -1
  64. package/node_modules/@sdd-agent-platform/core/dist/risk/contracts.d.ts +2 -2
  65. package/node_modules/@sdd-agent-platform/core/dist/risk/kernel.js +7 -7
  66. package/node_modules/@sdd-agent-platform/core/dist/risk/kernel.js.map +1 -1
  67. package/node_modules/@sdd-agent-platform/core/dist/risk/legacy-adapters.js +12 -27
  68. package/node_modules/@sdd-agent-platform/core/dist/risk/legacy-adapters.js.map +1 -1
  69. package/node_modules/@sdd-agent-platform/core/dist/risk/workflow-gates.js +6 -6
  70. package/node_modules/@sdd-agent-platform/core/dist/risk/workflow-gates.js.map +1 -1
  71. package/node_modules/@sdd-agent-platform/core/dist/router/agent-runtime-config.js +1 -1
  72. package/node_modules/@sdd-agent-platform/core/dist/router/agent-runtime-config.js.map +1 -1
  73. package/node_modules/@sdd-agent-platform/core/dist/router/routing.js +2 -4
  74. package/node_modules/@sdd-agent-platform/core/dist/router/routing.js.map +1 -1
  75. package/node_modules/@sdd-agent-platform/core/dist/router/runtime-import.d.ts +28 -0
  76. package/node_modules/@sdd-agent-platform/core/dist/router/runtime-import.js +383 -0
  77. package/node_modules/@sdd-agent-platform/core/dist/router/runtime-import.js.map +1 -0
  78. package/node_modules/@sdd-agent-platform/core/dist/router/stage-route-binding.d.ts +37 -0
  79. package/node_modules/@sdd-agent-platform/core/dist/router/stage-route-binding.js +227 -0
  80. package/node_modules/@sdd-agent-platform/core/dist/router/stage-route-binding.js.map +1 -0
  81. package/node_modules/@sdd-agent-platform/core/dist/router.d.ts +1 -0
  82. package/node_modules/@sdd-agent-platform/core/dist/router.js +1 -0
  83. package/node_modules/@sdd-agent-platform/core/dist/router.js.map +1 -1
  84. package/node_modules/@sdd-agent-platform/core/dist/run-state/artifacts.d.ts +16 -0
  85. package/node_modules/@sdd-agent-platform/core/dist/run-state/artifacts.js +6 -0
  86. package/node_modules/@sdd-agent-platform/core/dist/run-state/artifacts.js.map +1 -1
  87. package/node_modules/@sdd-agent-platform/core/dist/run-state/model.d.ts +20 -0
  88. package/node_modules/@sdd-agent-platform/core/dist/run-state/run-state.js +7 -7
  89. package/node_modules/@sdd-agent-platform/core/dist/run-state/run-state.js.map +1 -1
  90. package/node_modules/@sdd-agent-platform/core/dist/run-state/task-evidence.d.ts +1 -2
  91. package/node_modules/@sdd-agent-platform/core/dist/run-state/task-evidence.js +2 -9
  92. package/node_modules/@sdd-agent-platform/core/dist/run-state/task-evidence.js.map +1 -1
  93. package/node_modules/@sdd-agent-platform/core/dist/run-state/timing.d.ts +8 -0
  94. package/node_modules/@sdd-agent-platform/core/dist/run-state/timing.js +131 -0
  95. package/node_modules/@sdd-agent-platform/core/dist/run-state/timing.js.map +1 -0
  96. package/node_modules/@sdd-agent-platform/core/dist/runtime-analysis/build.js +1 -4
  97. package/node_modules/@sdd-agent-platform/core/dist/runtime-analysis/build.js.map +1 -1
  98. package/node_modules/@sdd-agent-platform/core/dist/runtime-analysis/findings.js +0 -39
  99. package/node_modules/@sdd-agent-platform/core/dist/runtime-analysis/findings.js.map +1 -1
  100. package/node_modules/@sdd-agent-platform/core/dist/runtime-analysis/model.d.ts +1 -17
  101. package/node_modules/@sdd-agent-platform/core/dist/runtime-paths.d.ts +10 -0
  102. package/node_modules/@sdd-agent-platform/core/dist/runtime-paths.js +65 -0
  103. package/node_modules/@sdd-agent-platform/core/dist/runtime-paths.js.map +1 -1
  104. package/node_modules/@sdd-agent-platform/core/dist/runtime-projection-p0.d.ts +64 -0
  105. package/node_modules/@sdd-agent-platform/core/dist/runtime-projection-p0.js +211 -0
  106. package/node_modules/@sdd-agent-platform/core/dist/runtime-projection-p0.js.map +1 -0
  107. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/artifact-depth.d.ts +14 -0
  108. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/artifact-depth.js +179 -0
  109. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/artifact-depth.js.map +1 -0
  110. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-parser.d.ts +5 -1
  111. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-parser.js +60 -22
  112. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-parser.js.map +1 -1
  113. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-rendering.js +2 -2
  114. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-rendering.js.map +1 -1
  115. package/node_modules/@sdd-agent-platform/core/dist/spec-entry.js +40 -0
  116. package/node_modules/@sdd-agent-platform/core/dist/spec-entry.js.map +1 -0
  117. package/node_modules/@sdd-agent-platform/core/dist/spec-manager-contracts.d.ts +12 -0
  118. package/node_modules/@sdd-agent-platform/core/dist/spec-manager-contracts.js +2 -0
  119. package/node_modules/@sdd-agent-platform/core/dist/spec-manager-contracts.js.map +1 -0
  120. package/node_modules/@sdd-agent-platform/core/dist/stage-artifacts.d.ts +55 -0
  121. package/node_modules/@sdd-agent-platform/core/dist/stage-artifacts.js +315 -0
  122. package/node_modules/@sdd-agent-platform/core/dist/stage-artifacts.js.map +1 -0
  123. package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration-contracts.d.ts +55 -0
  124. package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration-contracts.js +238 -0
  125. package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration-contracts.js.map +1 -0
  126. package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration.d.ts +736 -0
  127. package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration.js +4018 -0
  128. package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration.js.map +1 -0
  129. package/node_modules/@sdd-agent-platform/core/dist/stage-runtime/runtime.js +8 -1
  130. package/node_modules/@sdd-agent-platform/core/dist/stage-runtime/runtime.js.map +1 -1
  131. package/node_modules/@sdd-agent-platform/core/dist/status/project-status.js +25 -1
  132. package/node_modules/@sdd-agent-platform/core/dist/status/project-status.js.map +1 -1
  133. package/node_modules/@sdd-agent-platform/core/dist/storage/runtime-store.d.ts +170 -18
  134. package/node_modules/@sdd-agent-platform/core/dist/storage/runtime-store.js +597 -85
  135. package/node_modules/@sdd-agent-platform/core/dist/storage/runtime-store.js.map +1 -1
  136. package/node_modules/@sdd-agent-platform/core/dist/sync-back/apply.d.ts +1 -17
  137. package/node_modules/@sdd-agent-platform/core/dist/sync-back/apply.js +1 -242
  138. package/node_modules/@sdd-agent-platform/core/dist/sync-back/apply.js.map +1 -1
  139. package/node_modules/@sdd-agent-platform/core/dist/sync-back/inspect.d.ts +1 -110
  140. package/node_modules/@sdd-agent-platform/core/dist/sync-back/inspect.js +1 -496
  141. package/node_modules/@sdd-agent-platform/core/dist/sync-back/inspect.js.map +1 -1
  142. package/node_modules/@sdd-agent-platform/core/dist/sync-back.d.ts +1 -2
  143. package/node_modules/@sdd-agent-platform/core/dist/sync-back.js +1 -2
  144. package/node_modules/@sdd-agent-platform/core/dist/sync-back.js.map +1 -1
  145. package/node_modules/@sdd-agent-platform/core/dist/task-execution-contract.d.ts +167 -0
  146. package/node_modules/@sdd-agent-platform/core/dist/task-execution-contract.js +377 -0
  147. package/node_modules/@sdd-agent-platform/core/dist/task-execution-contract.js.map +1 -0
  148. package/node_modules/@sdd-agent-platform/core/dist/test-support/fixtures.js +329 -314
  149. package/node_modules/@sdd-agent-platform/core/dist/test-support/fixtures.js.map +1 -1
  150. package/node_modules/@sdd-agent-platform/core/dist/test-support/run-state.d.ts +1 -0
  151. package/node_modules/@sdd-agent-platform/core/dist/test-support/run-state.js +31 -0
  152. package/node_modules/@sdd-agent-platform/core/dist/test-support/run-state.js.map +1 -1
  153. package/node_modules/@sdd-agent-platform/core/dist/truth-reconciliation.d.ts +44 -0
  154. package/node_modules/@sdd-agent-platform/core/dist/truth-reconciliation.js +135 -0
  155. package/node_modules/@sdd-agent-platform/core/dist/truth-reconciliation.js.map +1 -0
  156. package/node_modules/@sdd-agent-platform/core/dist/tsconfig.tsbuildinfo +1 -1
  157. package/node_modules/@sdd-agent-platform/core/dist/verification/goal-verify.d.ts +0 -49
  158. package/node_modules/@sdd-agent-platform/core/dist/verification/goal-verify.js +1 -545
  159. package/node_modules/@sdd-agent-platform/core/dist/verification/goal-verify.js.map +1 -1
  160. package/node_modules/@sdd-agent-platform/core/dist/verification/rendering.d.ts +5 -7
  161. package/node_modules/@sdd-agent-platform/core/dist/verification/rendering.js +15 -55
  162. package/node_modules/@sdd-agent-platform/core/dist/verification/rendering.js.map +1 -1
  163. package/node_modules/@sdd-agent-platform/core/dist/verification/single-task-loop.js +1 -40
  164. package/node_modules/@sdd-agent-platform/core/dist/verification/single-task-loop.js.map +1 -1
  165. package/node_modules/@sdd-agent-platform/core/dist/verification/task-evidence-judgment.d.ts +49 -0
  166. package/node_modules/@sdd-agent-platform/core/dist/verification/task-evidence-judgment.js +521 -0
  167. package/node_modules/@sdd-agent-platform/core/dist/verification/task-evidence-judgment.js.map +1 -0
  168. package/node_modules/@sdd-agent-platform/core/dist/verification/test-runtime.d.ts +12 -2
  169. package/node_modules/@sdd-agent-platform/core/dist/verification/test-runtime.js +247 -112
  170. package/node_modules/@sdd-agent-platform/core/dist/verification/test-runtime.js.map +1 -1
  171. package/node_modules/@sdd-agent-platform/core/dist/verification/validation-cache.d.ts +26 -0
  172. package/node_modules/@sdd-agent-platform/core/dist/verification/validation-cache.js +73 -0
  173. package/node_modules/@sdd-agent-platform/core/dist/verification/validation-cache.js.map +1 -0
  174. package/node_modules/@sdd-agent-platform/core/dist/verification/verify-contract.d.ts +1 -1
  175. package/node_modules/@sdd-agent-platform/core/dist/verification/verify-contract.js +49 -72
  176. package/node_modules/@sdd-agent-platform/core/dist/verification/verify-contract.js.map +1 -1
  177. package/node_modules/@sdd-agent-platform/core/dist/verification.d.ts +3 -3
  178. package/node_modules/@sdd-agent-platform/core/dist/verification.js +2 -2
  179. package/node_modules/@sdd-agent-platform/core/dist/verification.js.map +1 -1
  180. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/evidence-packet.js +2 -7
  181. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/evidence-packet.js.map +1 -1
  182. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/hard-checks.js +0 -7
  183. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/hard-checks.js.map +1 -1
  184. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/policy.js +2 -4
  185. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/policy.js.map +1 -1
  186. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/types.d.ts +3 -5
  187. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/latest-eligible-run.js +30 -4
  188. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/latest-eligible-run.js.map +1 -1
  189. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/migration-recovery.d.ts +40 -0
  190. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/migration-recovery.js +110 -0
  191. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/migration-recovery.js.map +1 -0
  192. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/repair-contract.d.ts +12 -0
  193. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/repair-contract.js +63 -0
  194. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/repair-contract.js.map +1 -0
  195. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/resolve-task-run.d.ts +21 -0
  196. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/resolve-task-run.js +95 -0
  197. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/resolve-task-run.js.map +1 -0
  198. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/resolve.d.ts +55 -5
  199. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/resolve.js +518 -36
  200. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/resolve.js.map +1 -1
  201. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/runtime-projections.d.ts +228 -0
  202. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/runtime-projections.js +452 -0
  203. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/runtime-projections.js.map +1 -0
  204. package/node_modules/@sdd-agent-platform/core/package.json +6 -3
  205. package/node_modules/@sdd-agent-platform/core/src/ai-tools.test.ts +238 -137
  206. package/node_modules/@sdd-agent-platform/core/src/ai-tools.ts +84 -103
  207. package/node_modules/@sdd-agent-platform/core/src/artifacts/ingestion.test.ts +189 -189
  208. package/node_modules/@sdd-agent-platform/core/src/artifacts/ingestion.ts +222 -222
  209. package/node_modules/@sdd-agent-platform/core/src/artifacts/sdd-evidence.test.ts +28 -28
  210. package/node_modules/@sdd-agent-platform/core/src/artifacts/sdd-evidence.ts +302 -302
  211. package/node_modules/@sdd-agent-platform/core/src/artifacts/sdd-result.test.ts +181 -181
  212. package/node_modules/@sdd-agent-platform/core/src/artifacts/sdd-result.ts +231 -231
  213. package/node_modules/@sdd-agent-platform/core/src/artifacts/templates.ts +99 -99
  214. package/node_modules/@sdd-agent-platform/core/src/artifacts.ts +4 -4
  215. package/node_modules/@sdd-agent-platform/core/src/coding-facts/contracts.ts +79 -79
  216. package/node_modules/@sdd-agent-platform/core/src/coding-facts.ts +1 -1
  217. package/node_modules/@sdd-agent-platform/core/src/config/init-project.test.ts +314 -306
  218. package/node_modules/@sdd-agent-platform/core/src/config/init-project.ts +128 -120
  219. package/node_modules/@sdd-agent-platform/core/src/config/project-config.ts +265 -259
  220. package/node_modules/@sdd-agent-platform/core/src/config/project-detection.ts +147 -147
  221. package/node_modules/@sdd-agent-platform/core/src/config/starter-documents.ts +400 -445
  222. package/node_modules/@sdd-agent-platform/core/src/context/budget.ts +30 -30
  223. package/node_modules/@sdd-agent-platform/core/src/context/build-package.ts +305 -317
  224. package/node_modules/@sdd-agent-platform/core/src/context/command-summary.ts +45 -45
  225. package/node_modules/@sdd-agent-platform/core/src/context/context-build.test.ts +188 -188
  226. package/node_modules/@sdd-agent-platform/core/src/context/evidence-summary.ts +144 -144
  227. package/node_modules/@sdd-agent-platform/core/src/context/log-worker.ts +48 -48
  228. package/node_modules/@sdd-agent-platform/core/src/context/source-refs.ts +41 -41
  229. package/node_modules/@sdd-agent-platform/core/src/context-offload/contracts.ts +47 -47
  230. package/node_modules/@sdd-agent-platform/core/src/context-offload/runtime.test.ts +71 -71
  231. package/node_modules/@sdd-agent-platform/core/src/context-offload/runtime.ts +178 -178
  232. package/node_modules/@sdd-agent-platform/core/src/context-offload.ts +2 -2
  233. package/node_modules/@sdd-agent-platform/core/src/context.ts +6 -6
  234. package/node_modules/@sdd-agent-platform/core/src/contracts/issues.ts +13 -13
  235. package/node_modules/@sdd-agent-platform/core/src/contracts.test.ts +9 -9
  236. package/node_modules/@sdd-agent-platform/core/src/contracts.ts +121 -115
  237. package/node_modules/@sdd-agent-platform/core/src/delegation/delegation.test.ts +183 -183
  238. package/node_modules/@sdd-agent-platform/core/src/delegation/model.ts +23 -23
  239. package/node_modules/@sdd-agent-platform/core/src/delegation/queue.ts +58 -58
  240. package/node_modules/@sdd-agent-platform/core/src/delegation/run-state.ts +14 -14
  241. package/node_modules/@sdd-agent-platform/core/src/delegation/state-machine.ts +90 -90
  242. package/node_modules/@sdd-agent-platform/core/src/delegation/validation.ts +124 -124
  243. package/node_modules/@sdd-agent-platform/core/src/delegation.ts +26 -26
  244. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/ai-entries.ts +28 -28
  245. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/document-chain.ts +104 -112
  246. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/local-run-index.ts +27 -27
  247. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/project.ts +84 -84
  248. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/registries.ts +252 -252
  249. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/run-evidence.ts +330 -330
  250. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/run-records.ts +79 -79
  251. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/run-trust.ts +128 -128
  252. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/runtime-contracts.ts +300 -300
  253. package/node_modules/@sdd-agent-platform/core/src/doctor/doctor.test.ts +627 -657
  254. package/node_modules/@sdd-agent-platform/core/src/doctor/doctor.ts +301 -318
  255. package/node_modules/@sdd-agent-platform/core/src/doctor/model.ts +13 -13
  256. package/node_modules/@sdd-agent-platform/core/src/doctor/summary.ts +11 -11
  257. package/node_modules/@sdd-agent-platform/core/src/doctor.ts +2 -2
  258. package/node_modules/@sdd-agent-platform/core/src/evidence/lookup.ts +80 -80
  259. package/node_modules/@sdd-agent-platform/core/src/evidence-runtime/contracts.ts +48 -49
  260. package/node_modules/@sdd-agent-platform/core/src/evidence-runtime.ts +1 -1
  261. package/node_modules/@sdd-agent-platform/core/src/execution/agent-execution-records.ts +195 -195
  262. package/node_modules/@sdd-agent-platform/core/src/execution/background-executor.test.ts +187 -187
  263. package/node_modules/@sdd-agent-platform/core/src/execution/background-executor.ts +305 -305
  264. package/node_modules/@sdd-agent-platform/core/src/execution/foreground-subagents.test.ts +97 -97
  265. package/node_modules/@sdd-agent-platform/core/src/execution/foreground-subagents.ts +453 -453
  266. package/node_modules/@sdd-agent-platform/core/src/execution/host-invocation.ts +225 -225
  267. package/node_modules/@sdd-agent-platform/core/src/execution/resident-worker.test.ts +132 -132
  268. package/node_modules/@sdd-agent-platform/core/src/execution/resident-worker.ts +436 -436
  269. package/node_modules/@sdd-agent-platform/core/src/execution/stage-team-runtime.test.ts +102 -102
  270. package/node_modules/@sdd-agent-platform/core/src/execution/stage-team-runtime.ts +271 -271
  271. package/node_modules/@sdd-agent-platform/core/src/execution/wave-executor.test.ts +111 -111
  272. package/node_modules/@sdd-agent-platform/core/src/execution/wave-executor.ts +231 -231
  273. package/node_modules/@sdd-agent-platform/core/src/execution.ts +5 -5
  274. package/node_modules/@sdd-agent-platform/core/src/governance/policy.test.ts +57 -57
  275. package/node_modules/@sdd-agent-platform/core/src/governance/policy.ts +175 -175
  276. package/node_modules/@sdd-agent-platform/core/src/governance.ts +1 -1
  277. package/node_modules/@sdd-agent-platform/core/src/instructions.test.ts +80 -49
  278. package/node_modules/@sdd-agent-platform/core/src/instructions.ts +38 -81
  279. package/node_modules/@sdd-agent-platform/core/src/lifecycle/decision-gate.test.ts +174 -174
  280. package/node_modules/@sdd-agent-platform/core/src/lifecycle/decision-gate.ts +373 -373
  281. package/node_modules/@sdd-agent-platform/core/src/lifecycle/rendering.ts +29 -29
  282. package/node_modules/@sdd-agent-platform/core/src/lifecycle/risk-signals.ts +146 -146
  283. package/node_modules/@sdd-agent-platform/core/src/lifecycle/ship.test.ts +47 -0
  284. package/node_modules/@sdd-agent-platform/core/src/lifecycle/ship.ts +255 -263
  285. package/node_modules/@sdd-agent-platform/core/src/lifecycle-graph/contracts.ts +179 -0
  286. package/node_modules/@sdd-agent-platform/core/src/lifecycle-graph/kernel.ts +522 -0
  287. package/node_modules/@sdd-agent-platform/core/src/lifecycle-graph.ts +2 -0
  288. package/node_modules/@sdd-agent-platform/core/src/lifecycle.ts +4 -4
  289. package/node_modules/@sdd-agent-platform/core/src/orchestration/contracts.ts +50 -50
  290. package/node_modules/@sdd-agent-platform/core/src/orchestration/index.ts +2 -2
  291. package/node_modules/@sdd-agent-platform/core/src/orchestration/runtime.ts +331 -342
  292. package/node_modules/@sdd-agent-platform/core/src/path-safety.test.ts +22 -22
  293. package/node_modules/@sdd-agent-platform/core/src/phase8-contracts.test.ts +243 -243
  294. package/node_modules/@sdd-agent-platform/core/src/phase8-projection-compat.test.ts +152 -153
  295. package/node_modules/@sdd-agent-platform/core/src/phase8-risk-kernel.test.ts +277 -277
  296. package/node_modules/@sdd-agent-platform/core/src/phase9-lifecycle-graph.test.ts +103 -0
  297. package/node_modules/@sdd-agent-platform/core/src/planning/task-graph.test.ts +88 -88
  298. package/node_modules/@sdd-agent-platform/core/src/planning/task-graph.ts +222 -222
  299. package/node_modules/@sdd-agent-platform/core/src/planning/wave-plan.test.ts +79 -79
  300. package/node_modules/@sdd-agent-platform/core/src/planning/wave-plan.ts +160 -160
  301. package/node_modules/@sdd-agent-platform/core/src/planning.ts +2 -2
  302. package/node_modules/@sdd-agent-platform/core/src/registries/agent-capability-catalog.ts +426 -426
  303. package/node_modules/@sdd-agent-platform/core/src/registries/agent-registry.ts +230 -146
  304. package/node_modules/@sdd-agent-platform/core/src/registries/agent-runtime-static.ts +142 -142
  305. package/node_modules/@sdd-agent-platform/core/src/registries/capability-sources.ts +253 -253
  306. package/node_modules/@sdd-agent-platform/core/src/registries/command-team-runtime.ts +302 -309
  307. package/node_modules/@sdd-agent-platform/core/src/registries/eval-learning-context.ts +246 -246
  308. package/node_modules/@sdd-agent-platform/core/src/registries/plan-scout-domains.ts +89 -0
  309. package/node_modules/@sdd-agent-platform/core/src/registries/query-status.ts +119 -119
  310. package/node_modules/@sdd-agent-platform/core/src/registries/registries.test.ts +454 -429
  311. package/node_modules/@sdd-agent-platform/core/src/registries/skill-capabilities.ts +37 -37
  312. package/node_modules/@sdd-agent-platform/core/src/registries/tool-capabilities.ts +135 -135
  313. package/node_modules/@sdd-agent-platform/core/src/registries/tool-plugins.ts +132 -132
  314. package/node_modules/@sdd-agent-platform/core/src/registries/worker-adapters.ts +144 -144
  315. package/node_modules/@sdd-agent-platform/core/src/registries/workflow-gates.ts +111 -111
  316. package/node_modules/@sdd-agent-platform/core/src/registries.ts +42 -42
  317. package/node_modules/@sdd-agent-platform/core/src/risk/consumer-diagnostics.ts +98 -97
  318. package/node_modules/@sdd-agent-platform/core/src/risk/contracts.ts +63 -63
  319. package/node_modules/@sdd-agent-platform/core/src/risk/kernel.ts +233 -233
  320. package/node_modules/@sdd-agent-platform/core/src/risk/legacy-adapters.ts +251 -266
  321. package/node_modules/@sdd-agent-platform/core/src/risk/workflow-gates.ts +203 -203
  322. package/node_modules/@sdd-agent-platform/core/src/risk.ts +5 -5
  323. package/node_modules/@sdd-agent-platform/core/src/router/agent-runtime-config.ts +327 -327
  324. package/node_modules/@sdd-agent-platform/core/src/router/agent-runtime.ts +388 -388
  325. package/node_modules/@sdd-agent-platform/core/src/router/profile-resolution.ts +154 -154
  326. package/node_modules/@sdd-agent-platform/core/src/router/risk-policy.ts +33 -33
  327. package/node_modules/@sdd-agent-platform/core/src/router/route-cache.ts +100 -100
  328. package/node_modules/@sdd-agent-platform/core/src/router/route-projection.ts +356 -356
  329. package/node_modules/@sdd-agent-platform/core/src/router/route-sdd-task.test.ts +428 -428
  330. package/node_modules/@sdd-agent-platform/core/src/router/route-sdd-task.ts +2 -2
  331. package/node_modules/@sdd-agent-platform/core/src/router/routing-rules.ts +73 -73
  332. package/node_modules/@sdd-agent-platform/core/src/router/routing.ts +189 -191
  333. package/node_modules/@sdd-agent-platform/core/src/router/runtime-import.ts +464 -0
  334. package/node_modules/@sdd-agent-platform/core/src/router/runtime-inspection.ts +124 -124
  335. package/node_modules/@sdd-agent-platform/core/src/router/runtime-registry.ts +123 -123
  336. package/node_modules/@sdd-agent-platform/core/src/router/runtime-validation.ts +277 -277
  337. package/node_modules/@sdd-agent-platform/core/src/router/stage-route-binding.ts +273 -0
  338. package/node_modules/@sdd-agent-platform/core/src/router/team-mode.ts +170 -170
  339. package/node_modules/@sdd-agent-platform/core/src/router.ts +5 -4
  340. package/node_modules/@sdd-agent-platform/core/src/run-state/artifacts.ts +126 -118
  341. package/node_modules/@sdd-agent-platform/core/src/run-state/events.ts +27 -27
  342. package/node_modules/@sdd-agent-platform/core/src/run-state/inspect-run.ts +172 -172
  343. package/node_modules/@sdd-agent-platform/core/src/run-state/invocation-ledger.ts +109 -109
  344. package/node_modules/@sdd-agent-platform/core/src/run-state/model.ts +252 -230
  345. package/node_modules/@sdd-agent-platform/core/src/run-state/run-index.test.ts +52 -52
  346. package/node_modules/@sdd-agent-platform/core/src/run-state/run-index.ts +356 -356
  347. package/node_modules/@sdd-agent-platform/core/src/run-state/run-state.test.ts +70 -70
  348. package/node_modules/@sdd-agent-platform/core/src/run-state/run-state.ts +406 -406
  349. package/node_modules/@sdd-agent-platform/core/src/run-state/task-evidence.ts +198 -206
  350. package/node_modules/@sdd-agent-platform/core/src/run-state/timing.ts +146 -0
  351. package/node_modules/@sdd-agent-platform/core/src/run-state.ts +8 -8
  352. package/node_modules/@sdd-agent-platform/core/src/runtime-analysis/build.ts +60 -63
  353. package/node_modules/@sdd-agent-platform/core/src/runtime-analysis/findings.ts +257 -296
  354. package/node_modules/@sdd-agent-platform/core/src/runtime-analysis/model.ts +140 -152
  355. package/node_modules/@sdd-agent-platform/core/src/runtime-analysis.test.ts +66 -68
  356. package/node_modules/@sdd-agent-platform/core/src/runtime-analysis.ts +2 -2
  357. package/node_modules/@sdd-agent-platform/core/src/runtime-paths.ts +253 -176
  358. package/node_modules/@sdd-agent-platform/core/src/runtime-projection-p0.test.ts +101 -0
  359. package/node_modules/@sdd-agent-platform/core/src/runtime-projection-p0.ts +314 -0
  360. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/artifact-depth.test.ts +380 -0
  361. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/artifact-depth.ts +207 -0
  362. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/context.ts +111 -111
  363. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/document-hashes.ts +207 -207
  364. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/run-binding.ts +95 -95
  365. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/task-inspection.ts +39 -39
  366. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/task-parser.test.ts +467 -401
  367. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/task-parser.ts +738 -694
  368. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/task-rendering.ts +81 -81
  369. package/node_modules/@sdd-agent-platform/core/src/sdd-docs.ts +5 -5
  370. package/node_modules/@sdd-agent-platform/core/src/spec-manager-contracts.ts +13 -0
  371. package/node_modules/@sdd-agent-platform/core/src/stage-artifacts.ts +435 -0
  372. package/node_modules/@sdd-agent-platform/core/src/stage-collaboration-contracts.ts +316 -0
  373. package/node_modules/@sdd-agent-platform/core/src/stage-collaboration.test.ts +2964 -0
  374. package/node_modules/@sdd-agent-platform/core/src/stage-collaboration.ts +5856 -0
  375. package/node_modules/@sdd-agent-platform/core/src/stage-runtime/contracts.ts +40 -40
  376. package/node_modules/@sdd-agent-platform/core/src/stage-runtime/runtime.test.ts +209 -209
  377. package/node_modules/@sdd-agent-platform/core/src/stage-runtime/runtime.ts +360 -352
  378. package/node_modules/@sdd-agent-platform/core/src/stage-runtime.ts +2 -2
  379. package/node_modules/@sdd-agent-platform/core/src/status/project-status.test.ts +288 -288
  380. package/node_modules/@sdd-agent-platform/core/src/status/project-status.ts +651 -625
  381. package/node_modules/@sdd-agent-platform/core/src/status.ts +2 -2
  382. package/node_modules/@sdd-agent-platform/core/src/storage/json-io.ts +10 -10
  383. package/node_modules/@sdd-agent-platform/core/src/storage/runtime-store.test.ts +489 -489
  384. package/node_modules/@sdd-agent-platform/core/src/storage/runtime-store.ts +1981 -1175
  385. package/node_modules/@sdd-agent-platform/core/src/subagents/contracts.ts +45 -45
  386. package/node_modules/@sdd-agent-platform/core/src/subagents/runtime.test.ts +232 -232
  387. package/node_modules/@sdd-agent-platform/core/src/subagents/runtime.ts +307 -307
  388. package/node_modules/@sdd-agent-platform/core/src/subagents.ts +2 -2
  389. package/node_modules/@sdd-agent-platform/core/src/task-execution-contract.test.ts +141 -0
  390. package/node_modules/@sdd-agent-platform/core/src/task-execution-contract.ts +566 -0
  391. package/node_modules/@sdd-agent-platform/core/src/task-risk-profile.ts +193 -193
  392. package/node_modules/@sdd-agent-platform/core/src/test-support/fixtures.ts +413 -398
  393. package/node_modules/@sdd-agent-platform/core/src/test-support/run-state.ts +102 -70
  394. package/node_modules/@sdd-agent-platform/core/src/test-support.ts +2 -2
  395. package/node_modules/@sdd-agent-platform/core/src/truth-reconciliation.test.ts +72 -0
  396. package/node_modules/@sdd-agent-platform/core/src/truth-reconciliation.ts +174 -0
  397. package/node_modules/@sdd-agent-platform/core/src/verification/rendering.ts +137 -181
  398. package/node_modules/@sdd-agent-platform/core/src/verification/review-gate.test.ts +77 -77
  399. package/node_modules/@sdd-agent-platform/core/src/verification/review-gate.ts +77 -77
  400. package/node_modules/@sdd-agent-platform/core/src/verification/single-task-loop.ts +455 -494
  401. package/node_modules/@sdd-agent-platform/core/src/verification/{goal-verify.test.ts → task-evidence-judgment.test.ts} +261 -335
  402. package/node_modules/@sdd-agent-platform/core/src/verification/{goal-verify.ts → task-evidence-judgment.ts} +619 -648
  403. package/node_modules/@sdd-agent-platform/core/src/verification/test-runtime.ts +1190 -1032
  404. package/node_modules/@sdd-agent-platform/core/src/verification/validation-cache.ts +106 -0
  405. package/node_modules/@sdd-agent-platform/core/src/verification/validation-wave.ts +513 -513
  406. package/node_modules/@sdd-agent-platform/core/src/verification/verify-contract.ts +334 -358
  407. package/node_modules/@sdd-agent-platform/core/src/verification.ts +8 -8
  408. package/node_modules/@sdd-agent-platform/core/src/work-units/contracts.ts +26 -26
  409. package/node_modules/@sdd-agent-platform/core/src/work-units/runtime.test.ts +88 -88
  410. package/node_modules/@sdd-agent-platform/core/src/work-units/runtime.ts +112 -112
  411. package/node_modules/@sdd-agent-platform/core/src/work-units.ts +2 -2
  412. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/evidence-packet.ts +190 -196
  413. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/hard-checks.test.ts +169 -171
  414. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/hard-checks.ts +136 -143
  415. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/policy.test.ts +135 -137
  416. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/policy.ts +153 -155
  417. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/types.ts +111 -114
  418. package/node_modules/@sdd-agent-platform/core/src/workflow-state/affected-file-conflicts.ts +95 -95
  419. package/node_modules/@sdd-agent-platform/core/src/workflow-state/dependencies.test.ts +32 -32
  420. package/node_modules/@sdd-agent-platform/core/src/workflow-state/dependencies.ts +114 -114
  421. package/node_modules/@sdd-agent-platform/core/src/workflow-state/latest-eligible-run.ts +184 -156
  422. package/node_modules/@sdd-agent-platform/core/src/workflow-state/migration-recovery.ts +158 -0
  423. package/node_modules/@sdd-agent-platform/core/src/workflow-state/repair-contract.ts +77 -0
  424. package/node_modules/@sdd-agent-platform/core/src/workflow-state/resolve-task-run.ts +114 -0
  425. package/node_modules/@sdd-agent-platform/core/src/workflow-state/resolve.test.ts +970 -464
  426. package/node_modules/@sdd-agent-platform/core/src/workflow-state/resolve.ts +967 -363
  427. package/node_modules/@sdd-agent-platform/core/src/workflow-state/runtime-projections.ts +712 -0
  428. package/node_modules/@sdd-agent-platform/core/src/workflow-state.ts +2 -2
  429. package/node_modules/@sdd-agent-platform/core/src/worktree/isolation.ts +130 -130
  430. package/node_modules/@sdd-agent-platform/core/src/worktree/lifecycle.ts +269 -269
  431. package/node_modules/@sdd-agent-platform/core/src/worktree/worktree.test.ts +150 -150
  432. package/node_modules/@sdd-agent-platform/core/src/worktree.ts +2 -2
  433. package/node_modules/@sdd-agent-platform/core/tsconfig.json +15 -15
  434. package/package.json +2 -2
  435. package/packages/cli/dist/args.js +1 -1
  436. package/packages/cli/dist/args.js.map +1 -1
  437. package/packages/cli/dist/commands/context.js +1 -1
  438. package/packages/cli/dist/commands/context.js.map +1 -1
  439. package/packages/cli/dist/commands/evidence.js.map +1 -0
  440. package/packages/cli/dist/commands/execution.js +126 -0
  441. package/packages/cli/dist/commands/execution.js.map +1 -1
  442. package/packages/cli/dist/commands/instructions.d.ts +1 -1
  443. package/packages/cli/dist/commands/instructions.js +15 -1
  444. package/packages/cli/dist/commands/instructions.js.map +1 -1
  445. package/packages/cli/dist/commands/registry/runtime.js +70 -1
  446. package/packages/cli/dist/commands/registry/runtime.js.map +1 -1
  447. package/packages/cli/dist/commands/run.js +12 -1
  448. package/packages/cli/dist/commands/run.js.map +1 -1
  449. package/packages/cli/dist/commands/stage-close.d.ts +66 -0
  450. package/packages/cli/dist/commands/stage-close.js +524 -0
  451. package/packages/cli/dist/commands/stage-close.js.map +1 -0
  452. package/packages/cli/dist/commands/status.js +8 -1
  453. package/packages/cli/dist/commands/status.js.map +1 -1
  454. package/packages/cli/dist/commands/tasks.js.map +1 -1
  455. package/packages/cli/dist/dispatch.js +6 -31
  456. package/packages/cli/dist/dispatch.js.map +1 -1
  457. package/packages/cli/dist/help.js +153 -158
  458. package/packages/cli/dist/help.js.map +1 -1
  459. package/packages/cli/dist/renderers/workflow.d.ts +51 -2
  460. package/packages/cli/dist/renderers/workflow.js.map +1 -1
  461. package/packages/cli/dist/skill-import-args.d.ts +10 -0
  462. package/packages/cli/dist/skill-import-args.js +47 -0
  463. package/packages/cli/dist/skill-import-args.js.map +1 -0
  464. package/packages/cli/dist/tsconfig.tsbuildinfo +1 -1
  465. package/packages/cli/package.json +2 -2
  466. package/packages/core/dist/ai-tools.js +84 -103
  467. package/packages/core/dist/ai-tools.js.map +1 -1
  468. package/packages/core/dist/config/init-project.d.ts +10 -6
  469. package/packages/core/dist/config/init-project.js +7 -8
  470. package/packages/core/dist/config/init-project.js.map +1 -1
  471. package/packages/core/dist/config/project-config.d.ts +3 -1
  472. package/packages/core/dist/config/project-config.js +7 -3
  473. package/packages/core/dist/config/project-config.js.map +1 -1
  474. package/packages/core/dist/config/starter-documents.d.ts +0 -1
  475. package/packages/core/dist/config/starter-documents.js +374 -421
  476. package/packages/core/dist/config/starter-documents.js.map +1 -1
  477. package/packages/core/dist/context/build-package.d.ts +1 -1
  478. package/packages/core/dist/context/build-package.js +7 -19
  479. package/packages/core/dist/context/build-package.js.map +1 -1
  480. package/packages/core/dist/contracts.d.ts +7 -1
  481. package/packages/core/dist/contracts.js +6 -0
  482. package/packages/core/dist/contracts.js.map +1 -1
  483. package/packages/core/dist/doctor/checks/document-chain.js +2 -12
  484. package/packages/core/dist/doctor/checks/document-chain.js.map +1 -1
  485. package/packages/core/dist/doctor/doctor.js +1 -18
  486. package/packages/core/dist/doctor/doctor.js.map +1 -1
  487. package/packages/core/dist/evidence/lookup.d.ts +1 -1
  488. package/packages/core/dist/evidence/lookup.js +1 -1
  489. package/packages/core/dist/evidence/lookup.js.map +1 -1
  490. package/packages/core/dist/evidence-runtime/contracts.d.ts +0 -1
  491. package/packages/core/dist/evidence-runtime/coordination.js +110 -0
  492. package/packages/core/dist/evidence-runtime/coordination.js.map +1 -0
  493. package/packages/core/dist/execution/host-invocation.js +83 -83
  494. package/packages/core/dist/instructions.d.ts +1 -1
  495. package/packages/core/dist/instructions.js +37 -80
  496. package/packages/core/dist/instructions.js.map +1 -1
  497. package/packages/core/dist/lifecycle/ship.js +58 -68
  498. package/packages/core/dist/lifecycle/ship.js.map +1 -1
  499. package/packages/core/dist/lifecycle-graph/contracts.d.ts +159 -0
  500. package/packages/core/dist/lifecycle-graph/contracts.js +7 -0
  501. package/packages/core/dist/lifecycle-graph/contracts.js.map +1 -0
  502. package/packages/core/dist/lifecycle-graph/kernel.d.ts +16 -0
  503. package/packages/core/dist/lifecycle-graph/kernel.js +461 -0
  504. package/packages/core/dist/lifecycle-graph/kernel.js.map +1 -0
  505. package/packages/core/dist/lifecycle-graph.d.ts +2 -0
  506. package/packages/core/dist/lifecycle-graph.js +3 -0
  507. package/packages/core/dist/lifecycle-graph.js.map +1 -0
  508. package/packages/core/dist/orchestration/contracts.d.ts +1 -1
  509. package/packages/core/dist/orchestration/runtime.js +21 -28
  510. package/packages/core/dist/orchestration/runtime.js.map +1 -1
  511. package/packages/core/dist/registries/agent-registry.js +124 -40
  512. package/packages/core/dist/registries/agent-registry.js.map +1 -1
  513. package/packages/core/dist/registries/command-team-runtime.d.ts +1 -1
  514. package/packages/core/dist/registries/command-team-runtime.js +6 -13
  515. package/packages/core/dist/registries/command-team-runtime.js.map +1 -1
  516. package/packages/core/dist/registries/plan-scout-domains.d.ts +13 -0
  517. package/packages/core/dist/registries/plan-scout-domains.js +76 -0
  518. package/packages/core/dist/registries/plan-scout-domains.js.map +1 -0
  519. package/packages/core/dist/registries/skill-capabilities.js +7 -7
  520. package/packages/core/dist/registries/skill-capabilities.js.map +1 -1
  521. package/packages/core/dist/registries/tool-capabilities.js +6 -6
  522. package/packages/core/dist/registries/tool-capabilities.js.map +1 -1
  523. package/packages/core/dist/registries/workflow-gates.d.ts +1 -1
  524. package/packages/core/dist/registries/workflow-gates.js +18 -18
  525. package/packages/core/dist/registries/workflow-gates.js.map +1 -1
  526. package/packages/core/dist/risk/consumer-diagnostics.js +2 -1
  527. package/packages/core/dist/risk/consumer-diagnostics.js.map +1 -1
  528. package/packages/core/dist/risk/contracts.d.ts +2 -2
  529. package/packages/core/dist/risk/kernel.js +7 -7
  530. package/packages/core/dist/risk/kernel.js.map +1 -1
  531. package/packages/core/dist/risk/legacy-adapters.js +12 -27
  532. package/packages/core/dist/risk/legacy-adapters.js.map +1 -1
  533. package/packages/core/dist/risk/workflow-gates.js +6 -6
  534. package/packages/core/dist/risk/workflow-gates.js.map +1 -1
  535. package/packages/core/dist/router/agent-runtime-config.js +1 -1
  536. package/packages/core/dist/router/agent-runtime-config.js.map +1 -1
  537. package/packages/core/dist/router/routing.js +2 -4
  538. package/packages/core/dist/router/routing.js.map +1 -1
  539. package/packages/core/dist/router/runtime-import.d.ts +28 -0
  540. package/packages/core/dist/router/runtime-import.js +383 -0
  541. package/packages/core/dist/router/runtime-import.js.map +1 -0
  542. package/packages/core/dist/router/stage-route-binding.d.ts +37 -0
  543. package/packages/core/dist/router/stage-route-binding.js +227 -0
  544. package/packages/core/dist/router/stage-route-binding.js.map +1 -0
  545. package/packages/core/dist/router.d.ts +1 -0
  546. package/packages/core/dist/router.js +1 -0
  547. package/packages/core/dist/router.js.map +1 -1
  548. package/packages/core/dist/run-state/artifacts.d.ts +16 -0
  549. package/packages/core/dist/run-state/artifacts.js +6 -0
  550. package/packages/core/dist/run-state/artifacts.js.map +1 -1
  551. package/packages/core/dist/run-state/model.d.ts +20 -0
  552. package/packages/core/dist/run-state/run-state.js +7 -7
  553. package/packages/core/dist/run-state/run-state.js.map +1 -1
  554. package/packages/core/dist/run-state/task-evidence.d.ts +1 -2
  555. package/packages/core/dist/run-state/task-evidence.js +2 -9
  556. package/packages/core/dist/run-state/task-evidence.js.map +1 -1
  557. package/packages/core/dist/run-state/timing.d.ts +8 -0
  558. package/packages/core/dist/run-state/timing.js +131 -0
  559. package/packages/core/dist/run-state/timing.js.map +1 -0
  560. package/packages/core/dist/runtime-analysis/build.js +1 -4
  561. package/packages/core/dist/runtime-analysis/build.js.map +1 -1
  562. package/packages/core/dist/runtime-analysis/findings.js +0 -39
  563. package/packages/core/dist/runtime-analysis/findings.js.map +1 -1
  564. package/packages/core/dist/runtime-analysis/model.d.ts +1 -17
  565. package/packages/core/dist/runtime-paths.d.ts +10 -0
  566. package/packages/core/dist/runtime-paths.js +65 -0
  567. package/packages/core/dist/runtime-paths.js.map +1 -1
  568. package/packages/core/dist/runtime-projection-p0.d.ts +64 -0
  569. package/packages/core/dist/runtime-projection-p0.js +211 -0
  570. package/packages/core/dist/runtime-projection-p0.js.map +1 -0
  571. package/packages/core/dist/sdd-docs/artifact-depth.d.ts +14 -0
  572. package/packages/core/dist/sdd-docs/artifact-depth.js +179 -0
  573. package/packages/core/dist/sdd-docs/artifact-depth.js.map +1 -0
  574. package/packages/core/dist/sdd-docs/task-parser.d.ts +5 -1
  575. package/packages/core/dist/sdd-docs/task-parser.js +60 -22
  576. package/packages/core/dist/sdd-docs/task-parser.js.map +1 -1
  577. package/packages/core/dist/sdd-docs/task-rendering.js +2 -2
  578. package/packages/core/dist/sdd-docs/task-rendering.js.map +1 -1
  579. package/packages/core/dist/spec-entry.js +40 -0
  580. package/packages/core/dist/spec-entry.js.map +1 -0
  581. package/packages/core/dist/spec-manager-contracts.d.ts +12 -0
  582. package/packages/core/dist/spec-manager-contracts.js +2 -0
  583. package/packages/core/dist/spec-manager-contracts.js.map +1 -0
  584. package/packages/core/dist/stage-artifacts.d.ts +55 -0
  585. package/packages/core/dist/stage-artifacts.js +315 -0
  586. package/packages/core/dist/stage-artifacts.js.map +1 -0
  587. package/packages/core/dist/stage-collaboration-contracts.d.ts +55 -0
  588. package/packages/core/dist/stage-collaboration-contracts.js +238 -0
  589. package/packages/core/dist/stage-collaboration-contracts.js.map +1 -0
  590. package/packages/core/dist/stage-collaboration.d.ts +736 -0
  591. package/packages/core/dist/stage-collaboration.js +4018 -0
  592. package/packages/core/dist/stage-collaboration.js.map +1 -0
  593. package/packages/core/dist/stage-runtime/runtime.js +8 -1
  594. package/packages/core/dist/stage-runtime/runtime.js.map +1 -1
  595. package/packages/core/dist/status/project-status.js +25 -1
  596. package/packages/core/dist/status/project-status.js.map +1 -1
  597. package/packages/core/dist/storage/runtime-store.d.ts +170 -18
  598. package/packages/core/dist/storage/runtime-store.js +597 -85
  599. package/packages/core/dist/storage/runtime-store.js.map +1 -1
  600. package/packages/core/dist/sync-back/apply.d.ts +1 -17
  601. package/packages/core/dist/sync-back/apply.js +1 -242
  602. package/packages/core/dist/sync-back/apply.js.map +1 -1
  603. package/packages/core/dist/sync-back/inspect.d.ts +1 -110
  604. package/packages/core/dist/sync-back/inspect.js +1 -496
  605. package/packages/core/dist/sync-back/inspect.js.map +1 -1
  606. package/packages/core/dist/sync-back.d.ts +1 -2
  607. package/packages/core/dist/sync-back.js +1 -2
  608. package/packages/core/dist/sync-back.js.map +1 -1
  609. package/packages/core/dist/task-execution-contract.d.ts +167 -0
  610. package/packages/core/dist/task-execution-contract.js +377 -0
  611. package/packages/core/dist/task-execution-contract.js.map +1 -0
  612. package/packages/core/dist/test-support/fixtures.js +329 -314
  613. package/packages/core/dist/test-support/fixtures.js.map +1 -1
  614. package/packages/core/dist/test-support/run-state.d.ts +1 -0
  615. package/packages/core/dist/test-support/run-state.js +31 -0
  616. package/packages/core/dist/test-support/run-state.js.map +1 -1
  617. package/packages/core/dist/truth-reconciliation.d.ts +44 -0
  618. package/packages/core/dist/truth-reconciliation.js +135 -0
  619. package/packages/core/dist/truth-reconciliation.js.map +1 -0
  620. package/packages/core/dist/tsconfig.tsbuildinfo +1 -1
  621. package/packages/core/dist/verification/goal-verify.d.ts +0 -49
  622. package/packages/core/dist/verification/goal-verify.js +1 -545
  623. package/packages/core/dist/verification/goal-verify.js.map +1 -1
  624. package/packages/core/dist/verification/rendering.d.ts +5 -7
  625. package/packages/core/dist/verification/rendering.js +15 -55
  626. package/packages/core/dist/verification/rendering.js.map +1 -1
  627. package/packages/core/dist/verification/single-task-loop.js +1 -40
  628. package/packages/core/dist/verification/single-task-loop.js.map +1 -1
  629. package/packages/core/dist/verification/task-evidence-judgment.d.ts +49 -0
  630. package/packages/core/dist/verification/task-evidence-judgment.js +521 -0
  631. package/packages/core/dist/verification/task-evidence-judgment.js.map +1 -0
  632. package/packages/core/dist/verification/test-runtime.d.ts +12 -2
  633. package/packages/core/dist/verification/test-runtime.js +247 -112
  634. package/packages/core/dist/verification/test-runtime.js.map +1 -1
  635. package/packages/core/dist/verification/validation-cache.d.ts +26 -0
  636. package/packages/core/dist/verification/validation-cache.js +73 -0
  637. package/packages/core/dist/verification/validation-cache.js.map +1 -0
  638. package/packages/core/dist/verification/verify-contract.d.ts +1 -1
  639. package/packages/core/dist/verification/verify-contract.js +49 -72
  640. package/packages/core/dist/verification/verify-contract.js.map +1 -1
  641. package/packages/core/dist/verification.d.ts +3 -3
  642. package/packages/core/dist/verification.js +2 -2
  643. package/packages/core/dist/verification.js.map +1 -1
  644. package/packages/core/dist/workflow-gate/evidence-packet.js +2 -7
  645. package/packages/core/dist/workflow-gate/evidence-packet.js.map +1 -1
  646. package/packages/core/dist/workflow-gate/hard-checks.js +0 -7
  647. package/packages/core/dist/workflow-gate/hard-checks.js.map +1 -1
  648. package/packages/core/dist/workflow-gate/policy.js +2 -4
  649. package/packages/core/dist/workflow-gate/policy.js.map +1 -1
  650. package/packages/core/dist/workflow-gate/types.d.ts +3 -5
  651. package/packages/core/dist/workflow-state/latest-eligible-run.js +30 -4
  652. package/packages/core/dist/workflow-state/latest-eligible-run.js.map +1 -1
  653. package/packages/core/dist/workflow-state/migration-recovery.d.ts +40 -0
  654. package/packages/core/dist/workflow-state/migration-recovery.js +110 -0
  655. package/packages/core/dist/workflow-state/migration-recovery.js.map +1 -0
  656. package/packages/core/dist/workflow-state/repair-contract.d.ts +12 -0
  657. package/packages/core/dist/workflow-state/repair-contract.js +63 -0
  658. package/packages/core/dist/workflow-state/repair-contract.js.map +1 -0
  659. package/packages/core/dist/workflow-state/resolve-task-run.d.ts +21 -0
  660. package/packages/core/dist/workflow-state/resolve-task-run.js +95 -0
  661. package/packages/core/dist/workflow-state/resolve-task-run.js.map +1 -0
  662. package/packages/core/dist/workflow-state/resolve.d.ts +55 -5
  663. package/packages/core/dist/workflow-state/resolve.js +518 -36
  664. package/packages/core/dist/workflow-state/resolve.js.map +1 -1
  665. package/packages/core/dist/workflow-state/runtime-projections.d.ts +228 -0
  666. package/packages/core/dist/workflow-state/runtime-projections.js +452 -0
  667. package/packages/core/dist/workflow-state/runtime-projections.js.map +1 -0
  668. package/packages/core/package.json +6 -3
  669. package/tsconfig.build.json +6 -7
  670. package/node_modules/@sdd-agent-platform/core/dist/doctor/render.d.ts +0 -2
  671. package/node_modules/@sdd-agent-platform/core/dist/doctor/render.js +0 -44
  672. package/node_modules/@sdd-agent-platform/core/dist/doctor/render.js.map +0 -1
  673. package/node_modules/@sdd-agent-platform/core/src/sync-back/apply.ts +0 -270
  674. package/node_modules/@sdd-agent-platform/core/src/sync-back/inspect.ts +0 -655
  675. package/node_modules/@sdd-agent-platform/core/src/sync-back/sync-back.test.ts +0 -569
  676. package/node_modules/@sdd-agent-platform/core/src/sync-back.ts +0 -2
  677. package/node_modules/@sdd-agent-platform/core/src/verification/single-task-loop.test.ts +0 -255
  678. package/node_modules/@sdd-agent-platform/core/src/verification/test-runtime.test.ts +0 -439
  679. package/node_modules/@sdd-agent-platform/core/src/verification/validation-wave.test.ts +0 -341
  680. package/node_modules/@sdd-agent-platform/core/src/verification/verify-contract.test.ts +0 -204
  681. package/packages/cli/dist/commands/lifecycle.d.ts +0 -6
  682. package/packages/cli/dist/commands/lifecycle.js +0 -112
  683. package/packages/cli/dist/commands/lifecycle.js.map +0 -1
  684. package/packages/cli/dist/commands/sync-back.d.ts +0 -6
  685. package/packages/cli/dist/commands/sync-back.js +0 -82
  686. package/packages/cli/dist/commands/sync-back.js.map +0 -1
  687. package/packages/cli/dist/commands/test.d.ts +0 -6
  688. package/packages/cli/dist/commands/test.js +0 -195
  689. package/packages/cli/dist/commands/test.js.map +0 -1
  690. package/packages/cli/dist/commands/verifies.d.ts +0 -6
  691. package/packages/cli/dist/commands/verifies.js +0 -85
  692. package/packages/cli/dist/commands/verifies.js.map +0 -1
  693. package/packages/cli/dist/commands/verify.d.ts +0 -6
  694. package/packages/cli/dist/commands/verify.js +0 -134
  695. package/packages/cli/dist/commands/verify.js.map +0 -1
  696. package/packages/core/dist/doctor/render.d.ts +0 -2
  697. package/packages/core/dist/doctor/render.js +0 -44
  698. package/packages/core/dist/doctor/render.js.map +0 -1
@@ -1,464 +1,970 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import { mkdtemp, rm } 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 { validTaskMarkdown, writeBranchDocs } from '../test-support/fixtures.js';
12
- import { bindTestRunState, markTestRunReadyForSyncBack } from '../test-support/run-state.js';
13
- import { createDelegationRecord } from '../delegation/validation.js';
14
- import { resolveWorkflowState } from './resolve.js';
15
-
16
- const execFileAsync = promisify(execFile);
17
-
18
- test('workflow state resolver projects branch docs latest run and next action', async () => {
19
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-'));
20
- try {
21
- await initProject(root);
22
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
23
- const run = await createRun(root, { runId: 'run-1' });
24
- await bindTestRunState(root, run.runId, 'feature', 'T1');
25
- await markTestRunReadyForSyncBack(root, run.runId, 'T1');
26
-
27
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
28
-
29
- assert.equal(workflow.contract, 'phase-7.3-workflow-state-resolver-v1');
30
- assert.equal(workflow.workflowStatus, 'active');
31
- assert.equal(workflow.latestRun?.runId, 'run-1');
32
- assert.deepEqual(workflow.latestRunsByTask.map((entry) => `${entry.partition}:${entry.taskId}:${entry.runId}`), ['feature:T1:run-1']);
33
- assert.equal(workflow.taskCounts.total, 1);
34
- assert.equal(workflow.recommendedNextCommand, 'sdd ship --branch feature --dry-run');
35
- } finally {
36
- await rm(root, { recursive: true, force: true });
37
- }
38
- });
39
-
40
- test('workflow state routes validation PASS to ship without requiring sync-back proposal', async () => {
41
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-test-pass-'));
42
- try {
43
- await initProject(root);
44
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
45
- const run = await createRun(root, { runId: 'run-pass-no-syncback' });
46
- await bindTestRunState(root, run.runId, 'feature', 'T1');
47
- const bound = await readRunState(root, run.runId);
48
- await writeRunState(root, {
49
- ...bound,
50
- status: 'completed',
51
- validation: {
52
- status: 'pass',
53
- commands: ['npm test'],
54
- evidence: ['artifacts/validation-T1.md']
55
- },
56
- syncBack: {
57
- ...bound.syncBack,
58
- status: 'not_created'
59
- }
60
- });
61
-
62
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
63
-
64
- assert.equal(workflow.nextIntent.stage, 'ship');
65
- assert.equal(workflow.nextIntent.intent, 'ship_readiness');
66
- assert.equal(workflow.recommendedNextCommand, 'sdd ship --branch feature --dry-run');
67
- } finally {
68
- await rm(root, { recursive: true, force: true });
69
- }
70
- });
71
-
72
- test('workflow state resolver reports affected-file conflicts without run-index rebuild', async () => {
73
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-conflict-'));
74
- try {
75
- await initProject(root);
76
- 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')}`);
77
- const runA = await createRun(root, { runId: 'run-a' });
78
- await bindTestRunState(root, runA.runId, 'feature', 'T1');
79
- await markTestRunReadyForSyncBack(root, runA.runId, 'T1');
80
- const runB = await createRun(root, { runId: 'run-b' });
81
- await bindTestRunState(root, runB.runId, 'feature', 'T2');
82
- const archived = await createRun(root, { runId: 'run-c' });
83
- await writeRunState(root, { ...archived, status: 'archived' });
84
-
85
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
86
-
87
- assert.deepEqual(workflow.affectedFileConflicts.map((entry) => entry.runId), ['run-b']);
88
- assert.equal(workflow.blockingReasons.some((reason) => reason.includes('src/shared.ts')), true);
89
- } finally {
90
- await rm(root, { recursive: true, force: true });
91
- }
92
- });
93
-
94
- test('workflow state ignores superseded failed and foreground observer conflict candidates', async () => {
95
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-filtered-conflicts-'));
96
- try {
97
- await initProject(root);
98
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []).replace('packages/core/src/index.ts', 'docs/t1.md'));
99
- const failed = await createRun(root, { runId: 'run-failed' });
100
- await bindTestRunState(root, failed.runId, 'feature', 'T1');
101
- await writeRunState(root, {
102
- ...await readRunState(root, failed.runId),
103
- status: 'failed',
104
- validation: { status: 'fail', commands: ['npm test'], evidence: [] }
105
- });
106
- const observer = await createRun(root, { runId: 'run-observer' });
107
- await bindTestRunState(root, observer.runId, 'feature', 'T1');
108
- const delegation = createDelegationRecord({
109
- delegationId: 'F-T1-observer-001',
110
- task: 'T1',
111
- agent: 'observer',
112
- runMode: 'foreground',
113
- blocking: false,
114
- requiredForPhaseExit: false,
115
- expectedArtifact: 'artifacts/observer-T1.md'
116
- });
117
- await writeRunState(root, {
118
- ...await readRunState(root, observer.runId),
119
- status: 'completed',
120
- phase: 'foreground-subagents',
121
- delegations: { [delegation.delegationId]: { ...delegation, status: 'COMPLETED', terminalEventAt: new Date().toISOString() } }
122
- });
123
- const retry = await createRun(root, { runId: 'run-retry' });
124
- await bindTestRunState(root, retry.runId, 'feature', 'T1');
125
- await markTestRunReadyForSyncBack(root, retry.runId, 'T1');
126
-
127
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
128
-
129
- assert.equal(workflow.latestRun?.runId, 'run-retry');
130
- assert.deepEqual(workflow.affectedFileConflicts, []);
131
- assert.equal(workflow.blockingReasons.some((reason) => reason.includes('Affected file')), false);
132
- } finally {
133
- await rm(root, { recursive: true, force: true });
134
- }
135
- });
136
-
137
- test('workflow state resolver surfaces dependency blockers and points next action upstream', async () => {
138
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-dependencies-'));
139
- try {
140
- await initProject(root);
141
- await writeBranchDocs(root, 'feature', `# Tasks\n\n${validTaskMarkdown('DEP1', [])}\n${validTaskMarkdown('DEP2', ['DEP1']).replace('packages/core/src/index.ts', 'docs/dep2.md')}`);
142
-
143
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'DEP2' });
144
-
145
- assert.deepEqual(workflow.dependencyBlockers.map((blocker) => `${blocker.taskId}->${blocker.dependencyId}`), ['DEP2->DEP1']);
146
- assert.equal(workflow.blockingReasons.some((reason) => reason.includes('DEP2 depends on DEP1')), true);
147
- assert.equal(workflow.recommendedNextCommand, 'sdd do task DEP1 --branch feature');
148
- } finally {
149
- await rm(root, { recursive: true, force: true });
150
- }
151
- });
152
-
153
- test('workflow state treats implemented batch dependency as ready for downstream do', async () => {
154
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-runtime-dependency-ready-'));
155
- try {
156
- await initProject(root);
157
- await writeBranchDocs(root, 'feature', `# Tasks
158
-
159
- ${validTaskMarkdown('DEP1', [])
160
- .replace('packages/core/src/index.ts', 'docs/dep1.md')
161
- .replace('validation:\n - npm test', 'validation_batch: dep-batch\nvalidation_timing: batch_end\nrequires_verify_before_next: false\nvalidation:\n - npm test')}
162
- ${validTaskMarkdown('DEP2', ['DEP1'])
163
- .replace('packages/core/src/index.ts', 'docs/dep2.md')
164
- .replace('validation:\n - npm test', 'validation_batch: dep-batch\nvalidation_timing: batch_end\nrequires_verify_before_next: false\nvalidation:\n - npm test')}`);
165
- const run = await createRun(root, { runId: 'run-dep1-implemented' });
166
- await bindTestRunState(root, run.runId, 'feature', 'DEP1');
167
- const bound = await readRunState(root, run.runId);
168
- await writeRunState(root, {
169
- ...bound,
170
- status: 'completed',
171
- tasks: {
172
- ...bound.tasks,
173
- DEP1: {
174
- status: 'implemented_pending_validation',
175
- implementationStatus: 'implemented',
176
- verificationStatus: 'pending_batch',
177
- validationBatch: 'dep-batch',
178
- validationTiming: 'batch_end',
179
- requiresVerifyBeforeNext: false,
180
- gaps: [],
181
- artifacts: []
182
- }
183
- }
184
- });
185
-
186
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'DEP2' });
187
-
188
- assert.deepEqual(workflow.dependencyBlockers, []);
189
- assert.equal(workflow.recommendedNextCommand, 'sdd do task DEP2 --branch feature');
190
- } finally {
191
- await rm(root, { recursive: true, force: true });
192
- }
193
- });
194
-
195
- test('workflow state blocks downstream do until strict dependency verification passes', async () => {
196
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-runtime-dependency-strict-'));
197
- try {
198
- await initProject(root);
199
- await writeBranchDocs(root, 'feature', `# Tasks
200
-
201
- ${validTaskMarkdown('DEP1', [])
202
- .replace('packages/core/src/index.ts', 'docs/dep1.md')
203
- .replace('validation:\n - npm test', 'validation_timing: task_end\nrequires_verify_before_next: true\nvalidation:\n - npm test')}
204
- ${validTaskMarkdown('DEP2', ['DEP1']).replace('packages/core/src/index.ts', 'docs/dep2.md')}`);
205
- const run = await createRun(root, { runId: 'run-dep1-strict-implemented' });
206
- await bindTestRunState(root, run.runId, 'feature', 'DEP1');
207
- const bound = await readRunState(root, run.runId);
208
- await writeRunState(root, {
209
- ...bound,
210
- status: 'completed',
211
- tasks: {
212
- ...bound.tasks,
213
- DEP1: {
214
- status: 'implemented_pending_validation',
215
- implementationStatus: 'implemented',
216
- verificationStatus: 'not_run',
217
- validationBatch: null,
218
- validationTiming: 'task_end',
219
- requiresVerifyBeforeNext: true,
220
- gaps: [],
221
- artifacts: []
222
- }
223
- }
224
- });
225
-
226
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'DEP2' });
227
-
228
- assert.deepEqual(workflow.dependencyBlockers.map((blocker) => `${blocker.taskId}->${blocker.dependencyId}`), ['DEP2->DEP1']);
229
- assert.equal(workflow.blockingReasons.some((reason) => reason.includes('has not passed required verification')), true);
230
- assert.equal(workflow.recommendedNextCommand, 'sdd test task DEP1 --branch feature');
231
- } finally {
232
- await rm(root, { recursive: true, force: true });
233
- }
234
- });
235
-
236
-
237
- test('latest eligible selector prefers older compatible evidence over newer strict-stale evidence', async () => {
238
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-eligible-'));
239
- try {
240
- await initProject(root);
241
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
242
- const compatible = await createRun(root, { runId: 'run-compatible' });
243
- await bindTestRunState(root, compatible.runId, 'feature', 'T1');
244
- await markTestRunReadyForSyncBack(root, compatible.runId, 'T1');
245
-
246
- const strictStale = await createRun(root, { runId: 'run-strict-stale' });
247
- await bindTestRunState(root, strictStale.runId, 'feature', 'T1');
248
- await markTestRunReadyForSyncBack(root, strictStale.runId, 'T1');
249
- const strictStaleState = await readRunState(root, strictStale.runId);
250
- await writeRunState(root, {
251
- ...strictStaleState,
252
- documentSnapshot: {
253
- ...strictStaleState.documentSnapshot,
254
- tasksContractHash: 'stale-tasks-contract-hash'
255
- }
256
- });
257
-
258
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
259
- const selection = workflow.latestEligibleRunsByTask.find((entry) => entry.taskId === 'T1');
260
-
261
- assert.equal(workflow.latestRun?.runId, 'run-compatible');
262
- assert.equal(selection?.selected?.runId, 'run-compatible');
263
- assert.deepEqual(selection?.rejected.map((entry) => `${entry.runId}:${entry.compatibility}`), ['run-strict-stale:strict_stale']);
264
- assert.equal(selection?.rejected[0]?.reasons.some((reason) => reason.includes('strict_stale')), true);
265
- } finally {
266
- await rm(root, { recursive: true, force: true });
267
- }
268
- });
269
-
270
- test('latest eligible selector rejects newer blocked runs and keeps older completed evidence eligible', async () => {
271
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-blocked-eligible-'));
272
- try {
273
- await initProject(root);
274
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
275
- const completed = await createRun(root, { runId: 'run-completed' });
276
- await bindTestRunState(root, completed.runId, 'feature', 'T1');
277
- await markTestRunReadyForSyncBack(root, completed.runId, 'T1');
278
-
279
- const blocked = await createRun(root, { runId: 'run-blocked' });
280
- await bindTestRunState(root, blocked.runId, 'feature', 'T1');
281
- await markTestRunReadyForSyncBack(root, blocked.runId, 'T1');
282
- await writeRunState(root, { ...await readRunState(root, blocked.runId), status: 'blocked' });
283
-
284
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
285
- const selection = workflow.latestEligibleRunsByTask.find((entry) => entry.taskId === 'T1');
286
-
287
- assert.equal(selection?.selected?.runId, 'run-completed');
288
- assert.equal(selection?.rejected.some((entry) => entry.runId === 'run-blocked' && entry.reasons.includes('Run is blocked.')), true);
289
- } finally {
290
- await rm(root, { recursive: true, force: true });
291
- }
292
- });
293
-
294
- test('latest eligible selector returns visible candidates and rejects archived or failed runs with reasons', async () => {
295
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-rejected-'));
296
- try {
297
- await initProject(root);
298
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', []));
299
- const failed = await createRun(root, { runId: 'run-failed' });
300
- await bindTestRunState(root, failed.runId, 'feature', 'T1');
301
- await writeRunState(root, {
302
- ...await readRunState(root, failed.runId),
303
- status: 'failed',
304
- validation: { status: 'fail', commands: ['npm test'], evidence: [] }
305
- });
306
- const archived = await createRun(root, { runId: 'run-archived' });
307
- await bindTestRunState(root, archived.runId, 'feature', 'T1');
308
- await writeRunState(root, { ...await readRunState(root, archived.runId), status: 'archived' });
309
-
310
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
311
- const selection = workflow.latestEligibleRunsByTask.find((entry) => entry.taskId === 'T1');
312
-
313
- assert.equal(workflow.latestRun, null);
314
- assert.deepEqual(selection?.candidates.map((entry) => entry.runId), ['run-failed']);
315
- assert.deepEqual(selection?.rejected.map((entry) => entry.runId).sort(), ['run-archived', 'run-failed']);
316
- assert.equal(selection?.rejected.some((entry) => entry.reasons.includes('Run failed.')), true);
317
- assert.equal(selection?.rejected.some((entry) => entry.reasons.includes('Run is archived.')), true);
318
- } finally {
319
- await rm(root, { recursive: true, force: true });
320
- }
321
- });
322
-
323
- test('workflow state uses explicit partition runtime despite divergent git branch', async () => {
324
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-divergent-'));
325
- try {
326
- await initProject(root);
327
- await execFileAsync('git', ['init'], { cwd: root });
328
- await execFileAsync('git', ['checkout', '-b', 'current-branch'], { cwd: root });
329
- await writeBranchDocs(root, 'feature', validTaskMarkdown('T1', [])
330
- .replace('packages/core/src/index.ts', 'docs/t1.md')
331
- .replace('validation:\n - npm test', 'validation_timing: task_end\nrequires_verify_before_next: true\nvalidation:\n - npm test'));
332
- const divergent = await createRun(root, { runId: 'run-divergent' });
333
- await bindTestRunState(root, divergent.runId, 'feature', 'T1');
334
- const bound = await readRunState(root, divergent.runId);
335
- await writeRunState(root, {
336
- ...bound,
337
- status: 'completed',
338
- tasks: {
339
- ...bound.tasks,
340
- T1: {
341
- status: 'implemented_pending_validation',
342
- implementationStatus: 'implemented',
343
- verificationStatus: 'not_run',
344
- validationBatch: null,
345
- validationTiming: 'task_end',
346
- requiresVerifyBeforeNext: true,
347
- gaps: [],
348
- artifacts: []
349
- }
350
- }
351
- });
352
-
353
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'T1' });
354
- const selection = workflow.latestEligibleRunsByTask.find((entry) => entry.taskId === 'T1');
355
-
356
- assert.equal(workflow.latestRun?.runId, 'run-divergent');
357
- assert.equal(selection?.selected?.runId, 'run-divergent');
358
- assert.deepEqual(selection?.rejected.map((entry) => entry.runId), []);
359
- assert.equal(workflow.nextIntent.intent, 'run_task_validation');
360
- assert.equal(workflow.recommendedNextCommand, 'sdd test task T1 --branch feature');
361
- } finally {
362
- await rm(root, { recursive: true, force: true });
363
- }
364
- });
365
-
366
- test('workflow state recommends wave validation for implemented wave_end boundary', async () => {
367
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-wave-boundary-'));
368
- try {
369
- await initProject(root);
370
- await writeBranchDocs(root, 'feature', `# Tasks
371
-
372
- ${validTaskMarkdown('W1', [])
373
- .replace('packages/core/src/index.ts', 'docs/w1.md')
374
- .replace('validation:\n - npm test', 'validation_batch: docs-wave\nvalidation_timing: wave_end\nrequires_verify_before_next: false\nvalidation:\n - npm test')}`);
375
- const run = await createRun(root, { runId: 'run-w1-implemented' });
376
- await bindTestRunState(root, run.runId, 'feature', 'W1');
377
- const bound = await readRunState(root, run.runId);
378
- await writeRunState(root, {
379
- ...bound,
380
- status: 'completed',
381
- tasks: {
382
- ...bound.tasks,
383
- W1: {
384
- status: 'implemented_pending_validation',
385
- implementationStatus: 'implemented',
386
- verificationStatus: 'pending_batch',
387
- validationBatch: 'docs-wave',
388
- validationTiming: 'wave_end',
389
- requiresVerifyBeforeNext: false,
390
- gaps: [],
391
- artifacts: []
392
- }
393
- }
394
- });
395
-
396
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'W1' });
397
-
398
- assert.equal(workflow.nextIntent.intent, 'run_wave_validation');
399
- assert.equal(workflow.recommendedNextCommand, 'sdd test wave --branch feature --wave 1');
400
- } finally {
401
- await rm(root, { recursive: true, force: true });
402
- }
403
- });
404
-
405
- test('workflow state dependency readiness ignores newer ineligible runtime state', async () => {
406
- const root = await mkdtemp(path.join(tmpdir(), 'sdd-workflow-state-eligible-runtime-'));
407
- try {
408
- await initProject(root);
409
- await writeBranchDocs(root, 'feature', `# Tasks
410
-
411
- ${validTaskMarkdown('DEP1', [])
412
- .replace('packages/core/src/index.ts', 'docs/dep1.md')
413
- .replace('validation:\n - npm test', 'validation_batch: dep-batch\nvalidation_timing: batch_end\nrequires_verify_before_next: false\nvalidation:\n - npm test')}
414
- ${validTaskMarkdown('DEP2', ['DEP1']).replace('packages/core/src/index.ts', 'docs/dep2.md')}`);
415
- const eligible = await createRun(root, { runId: 'run-dep1-eligible' });
416
- await bindTestRunState(root, eligible.runId, 'feature', 'DEP1');
417
- const eligibleState = await readRunState(root, eligible.runId);
418
- await writeRunState(root, {
419
- ...eligibleState,
420
- status: 'completed',
421
- tasks: {
422
- ...eligibleState.tasks,
423
- DEP1: {
424
- status: 'implemented_pending_validation',
425
- implementationStatus: 'implemented',
426
- verificationStatus: 'pending_batch',
427
- validationBatch: 'dep-batch',
428
- validationTiming: 'batch_end',
429
- requiresVerifyBeforeNext: false,
430
- gaps: [],
431
- artifacts: []
432
- }
433
- }
434
- });
435
- const blocked = await createRun(root, { runId: 'run-dep1-blocked-newer' });
436
- await bindTestRunState(root, blocked.runId, 'feature', 'DEP1');
437
- const blockedState = await readRunState(root, blocked.runId);
438
- await writeRunState(root, {
439
- ...blockedState,
440
- status: 'blocked',
441
- updatedAt: new Date(Date.parse(eligibleState.updatedAt) + 1000).toISOString(),
442
- tasks: {
443
- ...blockedState.tasks,
444
- DEP1: {
445
- status: 'pending',
446
- implementationStatus: 'not_started',
447
- verificationStatus: 'not_run',
448
- validationBatch: 'dep-batch',
449
- validationTiming: 'batch_end',
450
- requiresVerifyBeforeNext: false,
451
- gaps: [],
452
- artifacts: []
453
- }
454
- }
455
- });
456
-
457
- const workflow = await resolveWorkflowState(root, { branch: 'feature', taskId: 'DEP2' });
458
-
459
- assert.deepEqual(workflow.dependencyBlockers, []);
460
- assert.equal(workflow.recommendedNextCommand, 'sdd test batch dep-batch --branch feature');
461
- } finally {
462
- await rm(root, { recursive: true, force: true });
463
- }
464
- });
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
+ };
970
+ }