sdd-agent-platform 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (417) hide show
  1. package/README.md +18 -23
  2. package/node_modules/@sdd-agent-platform/core/dist/ai-tools.js +31 -28
  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.js +3 -2
  5. package/node_modules/@sdd-agent-platform/core/dist/config/init-project.js.map +1 -1
  6. package/node_modules/@sdd-agent-platform/core/dist/config/starter-documents.d.ts +1 -1
  7. package/node_modules/@sdd-agent-platform/core/dist/config/starter-documents.js +14 -5
  8. package/node_modules/@sdd-agent-platform/core/dist/config/starter-documents.js.map +1 -1
  9. package/node_modules/@sdd-agent-platform/core/dist/contracts.d.ts +2 -0
  10. package/node_modules/@sdd-agent-platform/core/dist/contracts.js +2 -0
  11. package/node_modules/@sdd-agent-platform/core/dist/contracts.js.map +1 -1
  12. package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/run-evidence.js +3 -3
  13. package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/run-evidence.js.map +1 -1
  14. package/node_modules/@sdd-agent-platform/core/dist/doctor/doctor.js +155 -1
  15. package/node_modules/@sdd-agent-platform/core/dist/doctor/doctor.js.map +1 -1
  16. package/node_modules/@sdd-agent-platform/core/dist/evidence/lookup.d.ts +23 -0
  17. package/node_modules/@sdd-agent-platform/core/dist/evidence/lookup.js +54 -0
  18. package/node_modules/@sdd-agent-platform/core/dist/evidence/lookup.js.map +1 -0
  19. package/node_modules/@sdd-agent-platform/core/dist/evidence-runtime/contracts.d.ts +11 -0
  20. package/node_modules/@sdd-agent-platform/core/dist/execution/agent-execution-records.js +15 -8
  21. package/node_modules/@sdd-agent-platform/core/dist/execution/agent-execution-records.js.map +1 -1
  22. package/node_modules/@sdd-agent-platform/core/dist/execution/resident-worker.js +14 -6
  23. package/node_modules/@sdd-agent-platform/core/dist/execution/resident-worker.js.map +1 -1
  24. package/node_modules/@sdd-agent-platform/core/dist/execution/stage-team-runtime.d.ts +112 -0
  25. package/node_modules/@sdd-agent-platform/core/dist/execution/stage-team-runtime.js +145 -0
  26. package/node_modules/@sdd-agent-platform/core/dist/execution/stage-team-runtime.js.map +1 -0
  27. package/node_modules/@sdd-agent-platform/core/dist/instructions.js +36 -36
  28. package/node_modules/@sdd-agent-platform/core/dist/instructions.js.map +1 -1
  29. package/node_modules/@sdd-agent-platform/core/dist/lifecycle/ship.d.ts +2 -0
  30. package/node_modules/@sdd-agent-platform/core/dist/lifecycle/ship.js +37 -17
  31. package/node_modules/@sdd-agent-platform/core/dist/lifecycle/ship.js.map +1 -1
  32. package/node_modules/@sdd-agent-platform/core/dist/registries/agent-capability-catalog.d.ts +16 -1
  33. package/node_modules/@sdd-agent-platform/core/dist/registries/agent-capability-catalog.js +174 -16
  34. package/node_modules/@sdd-agent-platform/core/dist/registries/agent-capability-catalog.js.map +1 -1
  35. package/node_modules/@sdd-agent-platform/core/dist/registries/agent-registry.js +2 -2
  36. package/node_modules/@sdd-agent-platform/core/dist/registries/agent-registry.js.map +1 -1
  37. package/node_modules/@sdd-agent-platform/core/dist/registries/agent-runtime-static.d.ts +10 -0
  38. package/node_modules/@sdd-agent-platform/core/dist/registries/agent-runtime-static.js +31 -1
  39. package/node_modules/@sdd-agent-platform/core/dist/registries/agent-runtime-static.js.map +1 -1
  40. package/node_modules/@sdd-agent-platform/core/dist/registries/capability-sources.d.ts +2 -17
  41. package/node_modules/@sdd-agent-platform/core/dist/registries/capability-sources.js +222 -10
  42. package/node_modules/@sdd-agent-platform/core/dist/registries/capability-sources.js.map +1 -1
  43. package/node_modules/@sdd-agent-platform/core/dist/registries/workflow-gates.js +5 -5
  44. package/node_modules/@sdd-agent-platform/core/dist/registries/workflow-gates.js.map +1 -1
  45. package/node_modules/@sdd-agent-platform/core/dist/router/agent-runtime-config.js +27 -12
  46. package/node_modules/@sdd-agent-platform/core/dist/router/agent-runtime-config.js.map +1 -1
  47. package/node_modules/@sdd-agent-platform/core/dist/router/agent-runtime.d.ts +59 -1
  48. package/node_modules/@sdd-agent-platform/core/dist/router/route-projection.d.ts +3 -1
  49. package/node_modules/@sdd-agent-platform/core/dist/router/route-projection.js +191 -0
  50. package/node_modules/@sdd-agent-platform/core/dist/router/route-projection.js.map +1 -1
  51. package/node_modules/@sdd-agent-platform/core/dist/router/routing.js +32 -6
  52. package/node_modules/@sdd-agent-platform/core/dist/router/routing.js.map +1 -1
  53. package/node_modules/@sdd-agent-platform/core/dist/router/runtime-inspection.js +11 -4
  54. package/node_modules/@sdd-agent-platform/core/dist/router/runtime-inspection.js.map +1 -1
  55. package/node_modules/@sdd-agent-platform/core/dist/router/runtime-validation.js +31 -3
  56. package/node_modules/@sdd-agent-platform/core/dist/router/runtime-validation.js.map +1 -1
  57. package/node_modules/@sdd-agent-platform/core/dist/run-state/artifacts.js +48 -15
  58. package/node_modules/@sdd-agent-platform/core/dist/run-state/artifacts.js.map +1 -1
  59. package/node_modules/@sdd-agent-platform/core/dist/run-state/events.js +2 -2
  60. package/node_modules/@sdd-agent-platform/core/dist/run-state/events.js.map +1 -1
  61. package/node_modules/@sdd-agent-platform/core/dist/run-state/inspect-run.d.ts +3 -1
  62. package/node_modules/@sdd-agent-platform/core/dist/run-state/inspect-run.js +15 -49
  63. package/node_modules/@sdd-agent-platform/core/dist/run-state/inspect-run.js.map +1 -1
  64. package/node_modules/@sdd-agent-platform/core/dist/run-state/invocation-ledger.js +2 -2
  65. package/node_modules/@sdd-agent-platform/core/dist/run-state/invocation-ledger.js.map +1 -1
  66. package/node_modules/@sdd-agent-platform/core/dist/run-state/model.d.ts +25 -1
  67. package/node_modules/@sdd-agent-platform/core/dist/run-state/run-state.js +21 -14
  68. package/node_modules/@sdd-agent-platform/core/dist/run-state/run-state.js.map +1 -1
  69. package/node_modules/@sdd-agent-platform/core/dist/run-state/task-evidence.d.ts +62 -0
  70. package/node_modules/@sdd-agent-platform/core/dist/run-state/task-evidence.js +130 -0
  71. package/node_modules/@sdd-agent-platform/core/dist/run-state/task-evidence.js.map +1 -0
  72. package/node_modules/@sdd-agent-platform/core/dist/run-state.d.ts +1 -0
  73. package/node_modules/@sdd-agent-platform/core/dist/run-state.js +1 -0
  74. package/node_modules/@sdd-agent-platform/core/dist/run-state.js.map +1 -1
  75. package/node_modules/@sdd-agent-platform/core/dist/runtime-paths.d.ts +10 -0
  76. package/node_modules/@sdd-agent-platform/core/dist/runtime-paths.js +44 -14
  77. package/node_modules/@sdd-agent-platform/core/dist/runtime-paths.js.map +1 -1
  78. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/context.js +1 -1
  79. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/context.js.map +1 -1
  80. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/document-hashes.d.ts +4 -0
  81. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/document-hashes.js +189 -0
  82. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/document-hashes.js.map +1 -0
  83. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/run-binding.js +12 -3
  84. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/run-binding.js.map +1 -1
  85. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-parser.d.ts +20 -0
  86. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-parser.js +101 -21
  87. package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-parser.js.map +1 -1
  88. package/node_modules/@sdd-agent-platform/core/dist/status/project-status.d.ts +62 -1
  89. package/node_modules/@sdd-agent-platform/core/dist/status/project-status.js +192 -4
  90. package/node_modules/@sdd-agent-platform/core/dist/status/project-status.js.map +1 -1
  91. package/node_modules/@sdd-agent-platform/core/dist/storage/runtime-store.d.ts +195 -2
  92. package/node_modules/@sdd-agent-platform/core/dist/storage/runtime-store.js +499 -2
  93. package/node_modules/@sdd-agent-platform/core/dist/storage/runtime-store.js.map +1 -1
  94. package/node_modules/@sdd-agent-platform/core/dist/sync-back/apply.js +23 -1
  95. package/node_modules/@sdd-agent-platform/core/dist/sync-back/apply.js.map +1 -1
  96. package/node_modules/@sdd-agent-platform/core/dist/sync-back/inspect.d.ts +19 -0
  97. package/node_modules/@sdd-agent-platform/core/dist/sync-back/inspect.js +114 -12
  98. package/node_modules/@sdd-agent-platform/core/dist/sync-back/inspect.js.map +1 -1
  99. package/node_modules/@sdd-agent-platform/core/dist/test-support/fixtures.js +21 -0
  100. package/node_modules/@sdd-agent-platform/core/dist/test-support/fixtures.js.map +1 -1
  101. package/node_modules/@sdd-agent-platform/core/dist/test-support/run-state.js +16 -2
  102. package/node_modules/@sdd-agent-platform/core/dist/test-support/run-state.js.map +1 -1
  103. package/node_modules/@sdd-agent-platform/core/dist/tsconfig.tsbuildinfo +1 -1
  104. package/node_modules/@sdd-agent-platform/core/dist/verification/goal-verify.js +34 -2
  105. package/node_modules/@sdd-agent-platform/core/dist/verification/goal-verify.js.map +1 -1
  106. package/node_modules/@sdd-agent-platform/core/dist/verification/rendering.js +15 -5
  107. package/node_modules/@sdd-agent-platform/core/dist/verification/rendering.js.map +1 -1
  108. package/node_modules/@sdd-agent-platform/core/dist/verification/review-gate.d.ts +22 -0
  109. package/node_modules/@sdd-agent-platform/core/dist/verification/review-gate.js +53 -0
  110. package/node_modules/@sdd-agent-platform/core/dist/verification/review-gate.js.map +1 -0
  111. package/node_modules/@sdd-agent-platform/core/dist/verification/single-task-loop.js +102 -9
  112. package/node_modules/@sdd-agent-platform/core/dist/verification/single-task-loop.js.map +1 -1
  113. package/node_modules/@sdd-agent-platform/core/dist/verification/test-runtime.d.ts +16 -1
  114. package/node_modules/@sdd-agent-platform/core/dist/verification/test-runtime.js +355 -69
  115. package/node_modules/@sdd-agent-platform/core/dist/verification/test-runtime.js.map +1 -1
  116. package/node_modules/@sdd-agent-platform/core/dist/verification/validation-wave.d.ts +58 -0
  117. package/node_modules/@sdd-agent-platform/core/dist/verification/validation-wave.js +428 -0
  118. package/node_modules/@sdd-agent-platform/core/dist/verification/validation-wave.js.map +1 -0
  119. package/node_modules/@sdd-agent-platform/core/dist/verification/verify-contract.d.ts +2 -0
  120. package/node_modules/@sdd-agent-platform/core/dist/verification/verify-contract.js +116 -18
  121. package/node_modules/@sdd-agent-platform/core/dist/verification/verify-contract.js.map +1 -1
  122. package/node_modules/@sdd-agent-platform/core/dist/verification.d.ts +2 -0
  123. package/node_modules/@sdd-agent-platform/core/dist/verification.js +2 -0
  124. package/node_modules/@sdd-agent-platform/core/dist/verification.js.map +1 -1
  125. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/evidence-packet.d.ts +24 -0
  126. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/evidence-packet.js +182 -0
  127. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/evidence-packet.js.map +1 -0
  128. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/hard-checks.d.ts +4 -0
  129. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/hard-checks.js +130 -0
  130. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/hard-checks.js.map +1 -0
  131. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/policy.d.ts +4 -0
  132. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/policy.js +146 -0
  133. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/policy.js.map +1 -0
  134. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/types.d.ts +89 -0
  135. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/types.js +2 -0
  136. package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/types.js.map +1 -0
  137. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/affected-file-conflicts.d.ts +1 -0
  138. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/affected-file-conflicts.js +16 -1
  139. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/affected-file-conflicts.js.map +1 -1
  140. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/dependencies.d.ts +8 -4
  141. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/dependencies.js +25 -11
  142. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/dependencies.js.map +1 -1
  143. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/latest-eligible-run.d.ts +38 -0
  144. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/latest-eligible-run.js +122 -0
  145. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/latest-eligible-run.js.map +1 -0
  146. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/resolve.d.ts +27 -0
  147. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/resolve.js +166 -37
  148. package/node_modules/@sdd-agent-platform/core/dist/workflow-state/resolve.js.map +1 -1
  149. package/node_modules/@sdd-agent-platform/core/dist/workflow-state.d.ts +1 -0
  150. package/node_modules/@sdd-agent-platform/core/dist/workflow-state.js +1 -0
  151. package/node_modules/@sdd-agent-platform/core/dist/workflow-state.js.map +1 -1
  152. package/node_modules/@sdd-agent-platform/core/package.json +1 -1
  153. package/node_modules/@sdd-agent-platform/core/src/ai-tools.ts +31 -28
  154. package/node_modules/@sdd-agent-platform/core/src/artifacts/sdd-result.test.ts +50 -4
  155. package/node_modules/@sdd-agent-platform/core/src/config/init-project.test.ts +13 -10
  156. package/node_modules/@sdd-agent-platform/core/src/config/init-project.ts +3 -2
  157. package/node_modules/@sdd-agent-platform/core/src/config/starter-documents.ts +15 -5
  158. package/node_modules/@sdd-agent-platform/core/src/contracts.ts +2 -0
  159. package/node_modules/@sdd-agent-platform/core/src/doctor/checks/run-evidence.ts +3 -3
  160. package/node_modules/@sdd-agent-platform/core/src/doctor/doctor.test.ts +117 -5
  161. package/node_modules/@sdd-agent-platform/core/src/doctor/doctor.ts +164 -1
  162. package/node_modules/@sdd-agent-platform/core/src/evidence/lookup.ts +80 -0
  163. package/node_modules/@sdd-agent-platform/core/src/evidence-runtime/contracts.ts +12 -0
  164. package/node_modules/@sdd-agent-platform/core/src/execution/agent-execution-records.ts +16 -11
  165. package/node_modules/@sdd-agent-platform/core/src/execution/background-executor.test.ts +7 -0
  166. package/node_modules/@sdd-agent-platform/core/src/execution/resident-worker.test.ts +5 -0
  167. package/node_modules/@sdd-agent-platform/core/src/execution/resident-worker.ts +14 -6
  168. package/node_modules/@sdd-agent-platform/core/src/execution/stage-team-runtime.test.ts +102 -0
  169. package/node_modules/@sdd-agent-platform/core/src/execution/stage-team-runtime.ts +271 -0
  170. package/node_modules/@sdd-agent-platform/core/src/execution/wave-executor.test.ts +4 -0
  171. package/node_modules/@sdd-agent-platform/core/src/governance/policy.test.ts +2 -0
  172. package/node_modules/@sdd-agent-platform/core/src/instructions.test.ts +11 -5
  173. package/node_modules/@sdd-agent-platform/core/src/instructions.ts +36 -36
  174. package/node_modules/@sdd-agent-platform/core/src/lifecycle/ship.ts +39 -17
  175. package/node_modules/@sdd-agent-platform/core/src/phase8-contracts.test.ts +3 -2
  176. package/node_modules/@sdd-agent-platform/core/src/phase8-risk-kernel.test.ts +5 -0
  177. package/node_modules/@sdd-agent-platform/core/src/planning/task-graph.test.ts +2 -0
  178. package/node_modules/@sdd-agent-platform/core/src/planning/wave-plan.test.ts +3 -0
  179. package/node_modules/@sdd-agent-platform/core/src/registries/agent-capability-catalog.ts +269 -17
  180. package/node_modules/@sdd-agent-platform/core/src/registries/agent-registry.ts +2 -2
  181. package/node_modules/@sdd-agent-platform/core/src/registries/agent-runtime-static.ts +41 -1
  182. package/node_modules/@sdd-agent-platform/core/src/registries/capability-sources.ts +238 -15
  183. package/node_modules/@sdd-agent-platform/core/src/registries/registries.test.ts +27 -2
  184. package/node_modules/@sdd-agent-platform/core/src/registries/workflow-gates.ts +5 -5
  185. package/node_modules/@sdd-agent-platform/core/src/router/agent-runtime-config.ts +31 -12
  186. package/node_modules/@sdd-agent-platform/core/src/router/agent-runtime.ts +66 -1
  187. package/node_modules/@sdd-agent-platform/core/src/router/route-projection.ts +211 -0
  188. package/node_modules/@sdd-agent-platform/core/src/router/route-sdd-task.test.ts +151 -3
  189. package/node_modules/@sdd-agent-platform/core/src/router/routing.ts +35 -6
  190. package/node_modules/@sdd-agent-platform/core/src/router/runtime-inspection.ts +11 -4
  191. package/node_modules/@sdd-agent-platform/core/src/router/runtime-validation.ts +32 -3
  192. package/node_modules/@sdd-agent-platform/core/src/run-state/artifacts.ts +48 -15
  193. package/node_modules/@sdd-agent-platform/core/src/run-state/events.ts +2 -2
  194. package/node_modules/@sdd-agent-platform/core/src/run-state/inspect-run.ts +17 -52
  195. package/node_modules/@sdd-agent-platform/core/src/run-state/invocation-ledger.ts +2 -2
  196. package/node_modules/@sdd-agent-platform/core/src/run-state/model.ts +28 -1
  197. package/node_modules/@sdd-agent-platform/core/src/run-state/run-state.test.ts +3 -0
  198. package/node_modules/@sdd-agent-platform/core/src/run-state/run-state.ts +22 -18
  199. package/node_modules/@sdd-agent-platform/core/src/run-state/task-evidence.ts +206 -0
  200. package/node_modules/@sdd-agent-platform/core/src/run-state.ts +1 -0
  201. package/node_modules/@sdd-agent-platform/core/src/runtime-paths.ts +54 -14
  202. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/context.ts +1 -1
  203. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/document-hashes.ts +207 -0
  204. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/run-binding.ts +12 -3
  205. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/task-parser.test.ts +139 -0
  206. package/node_modules/@sdd-agent-platform/core/src/sdd-docs/task-parser.ts +137 -24
  207. package/node_modules/@sdd-agent-platform/core/src/status/project-status.ts +268 -5
  208. package/node_modules/@sdd-agent-platform/core/src/storage/runtime-store.test.ts +368 -4
  209. package/node_modules/@sdd-agent-platform/core/src/storage/runtime-store.ts +697 -2
  210. package/node_modules/@sdd-agent-platform/core/src/sync-back/apply.ts +23 -1
  211. package/node_modules/@sdd-agent-platform/core/src/sync-back/inspect.ts +145 -12
  212. package/node_modules/@sdd-agent-platform/core/src/sync-back/sync-back.test.ts +132 -9
  213. package/node_modules/@sdd-agent-platform/core/src/test-support/fixtures.ts +21 -0
  214. package/node_modules/@sdd-agent-platform/core/src/test-support/run-state.ts +16 -2
  215. package/node_modules/@sdd-agent-platform/core/src/verification/goal-verify.test.ts +1 -1
  216. package/node_modules/@sdd-agent-platform/core/src/verification/goal-verify.ts +38 -5
  217. package/node_modules/@sdd-agent-platform/core/src/verification/rendering.ts +15 -5
  218. package/node_modules/@sdd-agent-platform/core/src/verification/review-gate.test.ts +77 -0
  219. package/node_modules/@sdd-agent-platform/core/src/verification/review-gate.ts +77 -0
  220. package/node_modules/@sdd-agent-platform/core/src/verification/single-task-loop.test.ts +64 -4
  221. package/node_modules/@sdd-agent-platform/core/src/verification/single-task-loop.ts +110 -12
  222. package/node_modules/@sdd-agent-platform/core/src/verification/test-runtime.test.ts +72 -25
  223. package/node_modules/@sdd-agent-platform/core/src/verification/test-runtime.ts +402 -77
  224. package/node_modules/@sdd-agent-platform/core/src/verification/validation-wave.test.ts +341 -0
  225. package/node_modules/@sdd-agent-platform/core/src/verification/validation-wave.ts +513 -0
  226. package/node_modules/@sdd-agent-platform/core/src/verification/verify-contract.test.ts +144 -5
  227. package/node_modules/@sdd-agent-platform/core/src/verification/verify-contract.ts +129 -18
  228. package/node_modules/@sdd-agent-platform/core/src/verification.ts +2 -0
  229. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/evidence-packet.ts +196 -0
  230. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/hard-checks.test.ts +171 -0
  231. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/hard-checks.ts +143 -0
  232. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/policy.test.ts +137 -0
  233. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/policy.ts +155 -0
  234. package/node_modules/@sdd-agent-platform/core/src/workflow-gate/types.ts +114 -0
  235. package/node_modules/@sdd-agent-platform/core/src/workflow-state/affected-file-conflicts.ts +18 -1
  236. package/node_modules/@sdd-agent-platform/core/src/workflow-state/dependencies.test.ts +1 -1
  237. package/node_modules/@sdd-agent-platform/core/src/workflow-state/dependencies.ts +33 -11
  238. package/node_modules/@sdd-agent-platform/core/src/workflow-state/latest-eligible-run.ts +156 -0
  239. package/node_modules/@sdd-agent-platform/core/src/workflow-state/resolve.test.ts +351 -2
  240. package/node_modules/@sdd-agent-platform/core/src/workflow-state/resolve.ts +227 -39
  241. package/node_modules/@sdd-agent-platform/core/src/workflow-state.ts +1 -0
  242. package/package.json +1 -1
  243. package/packages/cli/dist/commands/status.js +2 -2
  244. package/packages/cli/dist/commands/status.js.map +1 -1
  245. package/packages/cli/dist/commands/sync-back.js +1 -1
  246. package/packages/cli/dist/commands/sync-back.js.map +1 -1
  247. package/packages/cli/dist/commands/tasks.js +4 -4
  248. package/packages/cli/dist/commands/tasks.js.map +1 -1
  249. package/packages/cli/dist/commands/test.js +94 -5
  250. package/packages/cli/dist/commands/test.js.map +1 -1
  251. package/packages/cli/dist/commands/verifies.js +5 -3
  252. package/packages/cli/dist/commands/verifies.js.map +1 -1
  253. package/packages/cli/dist/commands/verify.js +48 -7
  254. package/packages/cli/dist/commands/verify.js.map +1 -1
  255. package/packages/cli/dist/help.js +32 -18
  256. package/packages/cli/dist/help.js.map +1 -1
  257. package/packages/cli/dist/renderers/artifacts.js +1 -1
  258. package/packages/cli/dist/renderers/artifacts.js.map +1 -1
  259. package/packages/cli/dist/renderers/registry-runtime.js +7 -2
  260. package/packages/cli/dist/renderers/registry-runtime.js.map +1 -1
  261. package/packages/cli/dist/renderers/router.js +4 -2
  262. package/packages/cli/dist/renderers/router.js.map +1 -1
  263. package/packages/cli/dist/renderers/workflow.js +33 -12
  264. package/packages/cli/dist/renderers/workflow.js.map +1 -1
  265. package/packages/cli/dist/tsconfig.tsbuildinfo +1 -1
  266. package/packages/cli/package.json +2 -2
  267. package/packages/core/dist/ai-tools.js +31 -28
  268. package/packages/core/dist/ai-tools.js.map +1 -1
  269. package/packages/core/dist/config/init-project.js +3 -2
  270. package/packages/core/dist/config/init-project.js.map +1 -1
  271. package/packages/core/dist/config/starter-documents.d.ts +1 -1
  272. package/packages/core/dist/config/starter-documents.js +14 -5
  273. package/packages/core/dist/config/starter-documents.js.map +1 -1
  274. package/packages/core/dist/contracts.d.ts +2 -0
  275. package/packages/core/dist/contracts.js +2 -0
  276. package/packages/core/dist/contracts.js.map +1 -1
  277. package/packages/core/dist/doctor/checks/run-evidence.js +3 -3
  278. package/packages/core/dist/doctor/checks/run-evidence.js.map +1 -1
  279. package/packages/core/dist/doctor/doctor.js +155 -1
  280. package/packages/core/dist/doctor/doctor.js.map +1 -1
  281. package/packages/core/dist/evidence/lookup.d.ts +23 -0
  282. package/packages/core/dist/evidence/lookup.js +54 -0
  283. package/packages/core/dist/evidence/lookup.js.map +1 -0
  284. package/packages/core/dist/evidence-runtime/contracts.d.ts +11 -0
  285. package/packages/core/dist/execution/agent-execution-records.js +15 -8
  286. package/packages/core/dist/execution/agent-execution-records.js.map +1 -1
  287. package/packages/core/dist/execution/resident-worker.js +14 -6
  288. package/packages/core/dist/execution/resident-worker.js.map +1 -1
  289. package/packages/core/dist/execution/stage-team-runtime.d.ts +112 -0
  290. package/packages/core/dist/execution/stage-team-runtime.js +145 -0
  291. package/packages/core/dist/execution/stage-team-runtime.js.map +1 -0
  292. package/packages/core/dist/instructions.js +36 -36
  293. package/packages/core/dist/instructions.js.map +1 -1
  294. package/packages/core/dist/lifecycle/ship.d.ts +2 -0
  295. package/packages/core/dist/lifecycle/ship.js +37 -17
  296. package/packages/core/dist/lifecycle/ship.js.map +1 -1
  297. package/packages/core/dist/registries/agent-capability-catalog.d.ts +16 -1
  298. package/packages/core/dist/registries/agent-capability-catalog.js +174 -16
  299. package/packages/core/dist/registries/agent-capability-catalog.js.map +1 -1
  300. package/packages/core/dist/registries/agent-registry.js +2 -2
  301. package/packages/core/dist/registries/agent-registry.js.map +1 -1
  302. package/packages/core/dist/registries/agent-runtime-static.d.ts +10 -0
  303. package/packages/core/dist/registries/agent-runtime-static.js +31 -1
  304. package/packages/core/dist/registries/agent-runtime-static.js.map +1 -1
  305. package/packages/core/dist/registries/capability-sources.d.ts +2 -17
  306. package/packages/core/dist/registries/capability-sources.js +222 -10
  307. package/packages/core/dist/registries/capability-sources.js.map +1 -1
  308. package/packages/core/dist/registries/workflow-gates.js +5 -5
  309. package/packages/core/dist/registries/workflow-gates.js.map +1 -1
  310. package/packages/core/dist/router/agent-runtime-config.js +27 -12
  311. package/packages/core/dist/router/agent-runtime-config.js.map +1 -1
  312. package/packages/core/dist/router/agent-runtime.d.ts +59 -1
  313. package/packages/core/dist/router/route-projection.d.ts +3 -1
  314. package/packages/core/dist/router/route-projection.js +191 -0
  315. package/packages/core/dist/router/route-projection.js.map +1 -1
  316. package/packages/core/dist/router/routing.js +32 -6
  317. package/packages/core/dist/router/routing.js.map +1 -1
  318. package/packages/core/dist/router/runtime-inspection.js +11 -4
  319. package/packages/core/dist/router/runtime-inspection.js.map +1 -1
  320. package/packages/core/dist/router/runtime-validation.js +31 -3
  321. package/packages/core/dist/router/runtime-validation.js.map +1 -1
  322. package/packages/core/dist/run-state/artifacts.js +48 -15
  323. package/packages/core/dist/run-state/artifacts.js.map +1 -1
  324. package/packages/core/dist/run-state/events.js +2 -2
  325. package/packages/core/dist/run-state/events.js.map +1 -1
  326. package/packages/core/dist/run-state/inspect-run.d.ts +3 -1
  327. package/packages/core/dist/run-state/inspect-run.js +15 -49
  328. package/packages/core/dist/run-state/inspect-run.js.map +1 -1
  329. package/packages/core/dist/run-state/invocation-ledger.js +2 -2
  330. package/packages/core/dist/run-state/invocation-ledger.js.map +1 -1
  331. package/packages/core/dist/run-state/model.d.ts +25 -1
  332. package/packages/core/dist/run-state/run-state.js +21 -14
  333. package/packages/core/dist/run-state/run-state.js.map +1 -1
  334. package/packages/core/dist/run-state/task-evidence.d.ts +62 -0
  335. package/packages/core/dist/run-state/task-evidence.js +130 -0
  336. package/packages/core/dist/run-state/task-evidence.js.map +1 -0
  337. package/packages/core/dist/run-state.d.ts +1 -0
  338. package/packages/core/dist/run-state.js +1 -0
  339. package/packages/core/dist/run-state.js.map +1 -1
  340. package/packages/core/dist/runtime-paths.d.ts +10 -0
  341. package/packages/core/dist/runtime-paths.js +44 -14
  342. package/packages/core/dist/runtime-paths.js.map +1 -1
  343. package/packages/core/dist/sdd-docs/context.js +1 -1
  344. package/packages/core/dist/sdd-docs/context.js.map +1 -1
  345. package/packages/core/dist/sdd-docs/document-hashes.d.ts +4 -0
  346. package/packages/core/dist/sdd-docs/document-hashes.js +189 -0
  347. package/packages/core/dist/sdd-docs/document-hashes.js.map +1 -0
  348. package/packages/core/dist/sdd-docs/run-binding.js +12 -3
  349. package/packages/core/dist/sdd-docs/run-binding.js.map +1 -1
  350. package/packages/core/dist/sdd-docs/task-parser.d.ts +20 -0
  351. package/packages/core/dist/sdd-docs/task-parser.js +101 -21
  352. package/packages/core/dist/sdd-docs/task-parser.js.map +1 -1
  353. package/packages/core/dist/status/project-status.d.ts +62 -1
  354. package/packages/core/dist/status/project-status.js +192 -4
  355. package/packages/core/dist/status/project-status.js.map +1 -1
  356. package/packages/core/dist/storage/runtime-store.d.ts +195 -2
  357. package/packages/core/dist/storage/runtime-store.js +499 -2
  358. package/packages/core/dist/storage/runtime-store.js.map +1 -1
  359. package/packages/core/dist/sync-back/apply.js +23 -1
  360. package/packages/core/dist/sync-back/apply.js.map +1 -1
  361. package/packages/core/dist/sync-back/inspect.d.ts +19 -0
  362. package/packages/core/dist/sync-back/inspect.js +114 -12
  363. package/packages/core/dist/sync-back/inspect.js.map +1 -1
  364. package/packages/core/dist/test-support/fixtures.js +21 -0
  365. package/packages/core/dist/test-support/fixtures.js.map +1 -1
  366. package/packages/core/dist/test-support/run-state.js +16 -2
  367. package/packages/core/dist/test-support/run-state.js.map +1 -1
  368. package/packages/core/dist/tsconfig.tsbuildinfo +1 -1
  369. package/packages/core/dist/verification/goal-verify.js +34 -2
  370. package/packages/core/dist/verification/goal-verify.js.map +1 -1
  371. package/packages/core/dist/verification/rendering.js +15 -5
  372. package/packages/core/dist/verification/rendering.js.map +1 -1
  373. package/packages/core/dist/verification/review-gate.d.ts +22 -0
  374. package/packages/core/dist/verification/review-gate.js +53 -0
  375. package/packages/core/dist/verification/review-gate.js.map +1 -0
  376. package/packages/core/dist/verification/single-task-loop.js +102 -9
  377. package/packages/core/dist/verification/single-task-loop.js.map +1 -1
  378. package/packages/core/dist/verification/test-runtime.d.ts +16 -1
  379. package/packages/core/dist/verification/test-runtime.js +355 -69
  380. package/packages/core/dist/verification/test-runtime.js.map +1 -1
  381. package/packages/core/dist/verification/validation-wave.d.ts +58 -0
  382. package/packages/core/dist/verification/validation-wave.js +428 -0
  383. package/packages/core/dist/verification/validation-wave.js.map +1 -0
  384. package/packages/core/dist/verification/verify-contract.d.ts +2 -0
  385. package/packages/core/dist/verification/verify-contract.js +116 -18
  386. package/packages/core/dist/verification/verify-contract.js.map +1 -1
  387. package/packages/core/dist/verification.d.ts +2 -0
  388. package/packages/core/dist/verification.js +2 -0
  389. package/packages/core/dist/verification.js.map +1 -1
  390. package/packages/core/dist/workflow-gate/evidence-packet.d.ts +24 -0
  391. package/packages/core/dist/workflow-gate/evidence-packet.js +182 -0
  392. package/packages/core/dist/workflow-gate/evidence-packet.js.map +1 -0
  393. package/packages/core/dist/workflow-gate/hard-checks.d.ts +4 -0
  394. package/packages/core/dist/workflow-gate/hard-checks.js +130 -0
  395. package/packages/core/dist/workflow-gate/hard-checks.js.map +1 -0
  396. package/packages/core/dist/workflow-gate/policy.d.ts +4 -0
  397. package/packages/core/dist/workflow-gate/policy.js +146 -0
  398. package/packages/core/dist/workflow-gate/policy.js.map +1 -0
  399. package/packages/core/dist/workflow-gate/types.d.ts +89 -0
  400. package/packages/core/dist/workflow-gate/types.js +2 -0
  401. package/packages/core/dist/workflow-gate/types.js.map +1 -0
  402. package/packages/core/dist/workflow-state/affected-file-conflicts.d.ts +1 -0
  403. package/packages/core/dist/workflow-state/affected-file-conflicts.js +16 -1
  404. package/packages/core/dist/workflow-state/affected-file-conflicts.js.map +1 -1
  405. package/packages/core/dist/workflow-state/dependencies.d.ts +8 -4
  406. package/packages/core/dist/workflow-state/dependencies.js +25 -11
  407. package/packages/core/dist/workflow-state/dependencies.js.map +1 -1
  408. package/packages/core/dist/workflow-state/latest-eligible-run.d.ts +38 -0
  409. package/packages/core/dist/workflow-state/latest-eligible-run.js +122 -0
  410. package/packages/core/dist/workflow-state/latest-eligible-run.js.map +1 -0
  411. package/packages/core/dist/workflow-state/resolve.d.ts +27 -0
  412. package/packages/core/dist/workflow-state/resolve.js +166 -37
  413. package/packages/core/dist/workflow-state/resolve.js.map +1 -1
  414. package/packages/core/dist/workflow-state.d.ts +1 -0
  415. package/packages/core/dist/workflow-state.js +1 -0
  416. package/packages/core/dist/workflow-state.js.map +1 -1
  417. package/packages/core/package.json +1 -1
@@ -2,23 +2,28 @@ import { createHash } from 'node:crypto';
2
2
  import { spawn } from 'node:child_process';
3
3
  import { appendEvent } from '../run-state/events.js';
4
4
  import { appendInvocationLedgerEntry } from '../run-state/invocation-ledger.js';
5
- import type { RunState } from '../run-state/model.js';
5
+ import type { RunState, RunStateTaskRuntime } from '../run-state/model.js';
6
6
  import { createRun, readRunState, writeRunState } from '../run-state/run-state.js';
7
7
  import { writeArtifact } from '../run-state/artifacts.js';
8
8
  import { resolveSddContext } from '../sdd-docs/context.js';
9
9
  import { bindRunStateToTask } from '../sdd-docs/run-binding.js';
10
10
  import { parseSddBranch, type SddTask } from '../sdd-docs/task-parser.js';
11
- import { recordRuntimeProjection, recordRuntimeTestRun, recordRuntimeTestStep, runtimeScopedId } from '../storage/runtime-store.js';
11
+ import { inspectSddTask } from '../sdd-docs/task-inspection.js';
12
+ import { recordRuntimeAcceptanceEvidenceMap, recordRuntimeDurableGap, recordRuntimeProjection, recordRuntimeTestRun, recordRuntimeTestStep, recordRuntimeValidationEnvironmentSession, recordRuntimeValidationWaveRun, runtimeScopedId, updateRuntimeDurableGapStatus } from '../storage/runtime-store.js';
12
13
  import { ACCEPTANCE_POLICY_RULESET_VERSION, SDD_EVIDENCE_CONTRACT, SDD_EVIDENCE_VERSION, SDD_RESULT_CONTRACT, SDD_RESULT_VERSION, TEST_EVIDENCE_RUN_CONTRACT_VERSION, WORKFLOW_HANDOFF_CONTRACT_VERSION } from '../contracts.js';
13
14
  import type { LifecycleRiskDecision } from '../risk/contracts.js';
14
- import { inspectVerifyContract, writeVerifyContract, type VerifyContractInspection } from './verify-contract.js';
15
- import type { AcceptanceEvidenceCoverage, EvidenceCoverageStatus, TestEvidenceStatus, UnifiedTestEvidenceRun } from '../evidence-runtime.js';
15
+ import { inspectVerifyContract, type VerifyContractInspection } from './verify-contract.js';
16
+ import type { AcceptanceEvidenceCoverage, CapabilityEvidenceClassification, EvidenceCoverageStatus, TestEvidenceStatus, UnifiedTestEvidenceRun } from '../evidence-runtime.js';
16
17
  import { ensureTaskOrchestration, inspectOrchestrationGate } from '../orchestration/runtime.js';
17
18
  import { recordStageRunProjection, recordWorkflowHandoffProjection, validateWorkflowHandoff } from '../stage-runtime/runtime.js';
18
19
  import type { StageRun, WorkflowHandoff } from '../stage-runtime/contracts.js';
19
20
  import { evaluateTaskWorkflowGate, verifyContractBlockedGate, type ApprovalPolicy, type LifecycleRiskProfile, type LifecycleWorkflowGate } from '../risk.js';
20
21
  import { validateSddResultArtifact } from '../artifacts/sdd-result.js';
21
22
  import { dependencyBlockingReasonsForTask } from '../workflow-state/dependencies.js';
23
+ import { routeSddTask } from '../router/route-sdd-task.js';
24
+ import type { AgentCapabilityRouteDecision } from '../router/agent-runtime.js';
25
+ import { evaluateAndRecordWorkflowGateDecision } from '../workflow-gate/evidence-packet.js';
26
+ import type { WorkflowGateDecision, WorkflowGateStatus } from '../workflow-gate/types.js';
22
27
 
23
28
  const DEFAULT_TEST_TIMEOUT_MS = 120_000;
24
29
  const MAX_CAPTURE_BYTES = 256 * 1024;
@@ -53,20 +58,23 @@ interface NormalizedSddTestCommand {
53
58
  shell: boolean;
54
59
  }
55
60
 
56
- interface TestSyncBackProposal {
57
- path: string;
58
- digest: string;
59
- }
60
-
61
61
  type VerifyContractAction = 'none' | 'created' | 'refreshed' | 'blocked';
62
62
 
63
+ type RuntimeTestJudgment = WorkflowGateStatus;
64
+
63
65
  export interface SddTestResult {
64
66
  contract: 'sdd-test-runtime-v1';
65
67
  runId: string;
66
68
  testRunId: string;
69
+ validationWaveRunId: string;
70
+ validationEnvironmentSessionId: string;
67
71
  branch: string;
68
72
  taskId: string;
69
73
  status: SddTestStatus;
74
+ validationStatus: SddTestStatus;
75
+ workflowGateStatus: WorkflowGateStatus;
76
+ runtimeJudgment: RuntimeTestJudgment;
77
+ workflowGateDecision: WorkflowGateDecision;
70
78
  verifyContractStatus: string;
71
79
  verifyContractAction: VerifyContractAction;
72
80
  lifecycleGate: LifecycleWorkflowGate;
@@ -78,6 +86,7 @@ export interface SddTestResult {
78
86
  evidenceCoverage: EvidenceCoverageStatus;
79
87
  policyJudgment: TestEvidenceStatus;
80
88
  acceptanceCoverage: AcceptanceEvidenceCoverage[];
89
+ capabilityEvidence: CapabilityEvidenceClassification[];
81
90
  syncBackReady: boolean;
82
91
  commands: string[];
83
92
  steps: SddTestCommandStep[];
@@ -95,18 +104,16 @@ export interface RunSddTestOptions {
95
104
  commandInputs?: SddTestCommandInput[];
96
105
  timeoutMs?: number;
97
106
  approved?: boolean;
107
+ validationWave?: { waveRunId: string; environmentSessionId: string; taskIds: string[]; acceptanceRefsByTask?: Record<string, string[]> };
98
108
  }
99
109
 
100
110
  export async function runSddTest(projectRoot: string, options: RunSddTestOptions): Promise<SddTestResult> {
101
111
  const context = await resolveSddContext(projectRoot, { branch: options.branch ?? undefined, branchSource: options.branch ? 'cli_option' : undefined });
102
- let model = await parseSddBranch(projectRoot, context.partition);
103
- let task = model.tasks.find((candidate) => candidate.id === options.taskId) ?? null;
112
+ const model = await parseSddBranch(projectRoot, context.partition);
113
+ const inspected = inspectSddTask(model, options.taskId);
114
+ const task = inspected.task;
104
115
  const verifyContract = await ensureVerifyContractForTest(projectRoot, context.partition);
105
116
  const verifyInspection = verifyContract.inspection;
106
- if (verifyContract.action === 'created' || verifyContract.action === 'refreshed') {
107
- model = await parseSddBranch(projectRoot, context.partition);
108
- task = model.tasks.find((candidate) => candidate.id === options.taskId) ?? null;
109
- }
110
117
  const initialState = options.runId ? await readRunState(projectRoot, options.runId) : await createRun(projectRoot);
111
118
  const state = await bindRunStateToTask(projectRoot, initialState, context, model, task, options.taskId);
112
119
  const testRunId = runtimeScopedId(state.runId, options.taskId, new Date().toISOString(), 'sdd-test');
@@ -114,6 +121,35 @@ export async function runSddTest(projectRoot: string, options: RunSddTestOptions
114
121
  const commands = commandInputs.map((input) => input.command);
115
122
  const gaps: string[] = [];
116
123
  const startedAt = new Date().toISOString();
124
+ const ownsValidationWave = !options.validationWave;
125
+ const validationWaveRunId = options.validationWave?.waveRunId ?? runtimeScopedId(context.partition, options.taskId, state.runId, testRunId, 'validation-wave');
126
+ const validationEnvironmentSessionId = options.validationWave?.environmentSessionId ?? runtimeScopedId(context.partition, validationWaveRunId, 'validation-env');
127
+ const validationWaveTaskIds = options.validationWave?.taskIds ?? [options.taskId];
128
+ const validationWaveAcceptanceRefs = options.validationWave?.acceptanceRefsByTask?.[options.taskId];
129
+ if (ownsValidationWave) {
130
+ await recordRuntimeValidationEnvironmentSession(projectRoot, {
131
+ sessionId: validationEnvironmentSessionId,
132
+ partition: context.partition,
133
+ runId: state.runId,
134
+ waveRunId: validationWaveRunId,
135
+ status: 'active',
136
+ reuseKey: `${context.partition}:${options.taskId}`,
137
+ createdAt: startedAt,
138
+ updatedAt: startedAt,
139
+ payload: { contract: 'phase-8.17-validation-wave-runtime-v1', mode: 'single-task' }
140
+ });
141
+ await recordRuntimeValidationWaveRun(projectRoot, {
142
+ waveRunId: validationWaveRunId,
143
+ partition: context.partition,
144
+ runId: state.runId,
145
+ taskIds: validationWaveTaskIds,
146
+ status: 'RUNNING',
147
+ environmentSessionId: validationEnvironmentSessionId,
148
+ startedAt,
149
+ completedAt: startedAt,
150
+ payload: { contract: 'phase-8.17-validation-wave-runtime-v1', mode: 'single-task', taskId: options.taskId }
151
+ });
152
+ }
117
153
 
118
154
  await appendEvent(projectRoot, state.runId, {
119
155
  event: 'test_runtime_started',
@@ -126,6 +162,7 @@ export async function runSddTest(projectRoot: string, options: RunSddTestOptions
126
162
  gaps.push(`Task ${options.taskId} was not found in specs/${context.partition}/tasks.md.`);
127
163
  }
128
164
  if (task) {
165
+ gaps.push(...inspected.gaps.filter((gap) => gap.severity === 'blocking').map((gap) => `${gap.field}: ${gap.message}`));
129
166
  gaps.push(...dependencyBlockingReasonsForTask(model, options.taskId));
130
167
  }
131
168
  if (verifyContract.action === 'blocked') {
@@ -175,7 +212,7 @@ export async function runSddTest(projectRoot: string, options: RunSddTestOptions
175
212
  const steps: SddTestCommandStep[] = [];
176
213
  if (gaps.length === 0) {
177
214
  for (const [index, commandInput] of commandInputs.entries()) {
178
- const step = await runCommandStep(projectRoot, state.runId, context.partition, options.taskId, testRunId, index + 1, commandInput, acceptanceRefsForCommand(task, commandInput.command), options.timeoutMs ?? DEFAULT_TEST_TIMEOUT_MS);
215
+ const step = await runCommandStep(projectRoot, state.runId, context.partition, options.taskId, testRunId, index + 1, commandInput, acceptanceRefsForCommand(task, commandInput.command, validationWaveAcceptanceRefs), options.timeoutMs ?? DEFAULT_TEST_TIMEOUT_MS);
179
216
  steps.push(step);
180
217
  await appendEvent(projectRoot, state.runId, {
181
218
  event: 'test_step_completed',
@@ -187,18 +224,40 @@ export async function runSddTest(projectRoot: string, options: RunSddTestOptions
187
224
  }
188
225
 
189
226
  const commandStatus = deriveCommandStatus(gaps, steps);
190
- const acceptanceCoverage = buildAcceptanceCoverage(task, steps, commandStatus);
227
+ const acceptanceCoverage = buildAcceptanceCoverage(task, steps, commandStatus, validationWaveAcceptanceRefs);
191
228
  const evidenceCoverage = summarizeEvidenceCoverage(acceptanceCoverage);
192
229
  const policyJudgment = derivePolicyJudgment(commandStatus, evidenceCoverage);
193
- const status = policyJudgment;
194
- const syncBackReady = status === 'PASS';
195
- const validationArtifact = task ? await writeValidationArtifact(projectRoot, state.runId, task, status, steps, gaps) : null;
196
- const unifiedEvidence = buildUnifiedTestEvidenceRun(testRunId, context.partition, state.runId, options.taskId, commandStatus, evidenceCoverage, policyJudgment, steps, acceptanceCoverage, syncBackReady, gaps);
230
+ await recordAcceptanceEvidenceMaps(projectRoot, validationWaveRunId, testRunId, context.partition, state.runId, options.taskId, acceptanceCoverage);
231
+ const validationStatus = policyJudgment;
232
+ const syncBackReady = false;
233
+ const capabilityRoute = task ? await routeSddTask(projectRoot, { taskId: options.taskId, branch: context.partition, approved: options.approved }) : null;
234
+ const capabilityEvidence = buildCapabilityEvidenceClassification(capabilityRoute?.capabilityDecision ?? null, steps);
235
+ const validationArtifact = task ? await writeValidationArtifact(projectRoot, state.runId, task, validationStatus, steps, gaps, capabilityEvidence) : null;
236
+ const evidenceBeforeIndex = [validationArtifact?.runRelativePath, ...steps.map((step) => step.outputArtifact)].filter((item): item is string => Boolean(item));
237
+ await persistTestRunState(projectRoot, state, options.taskId, validationStatus, commands, evidenceBeforeIndex, validationArtifact?.runRelativePath ?? null);
238
+ await resolveTestRuntimeDurableGap(projectRoot, context.partition, state.runId, options.taskId, validationStatus, gaps);
239
+
240
+ const gateDecision = (await evaluateAndRecordWorkflowGateDecision(projectRoot, {
241
+ branch: context.partition,
242
+ taskId: options.taskId,
243
+ runId: state.runId,
244
+ decisionKind: 'test'
245
+ })).decision;
246
+ const runtimeJudgment = gateDecision.status;
247
+ const status = finalStatusForTest(validationStatus, runtimeJudgment);
248
+ await recordTestRuntimeDurableGap(projectRoot, context.partition, state.runId, options.taskId, status, validationStatus, runtimeJudgment, gaps, evidenceBeforeIndex);
249
+ const unifiedEvidence = buildUnifiedTestEvidenceRun(testRunId, context.partition, state.runId, options.taskId, commandStatus, evidenceCoverage, policyJudgment, status, runtimeJudgment, steps, acceptanceCoverage, capabilityEvidence, syncBackReady, gaps, workflowGate.nextAction, gateDecision);
197
250
  const indexArtifact = await writeIndexArtifact(projectRoot, state.runId, {
198
251
  testRunId,
252
+ validationWaveRunId,
253
+ validationEnvironmentSessionId,
199
254
  branch: context.partition,
200
255
  taskId: options.taskId,
201
256
  status,
257
+ validationStatus,
258
+ workflowGateStatus: gateDecision.status,
259
+ runtimeJudgment,
260
+ workflowGateDecision: gateDecision,
202
261
  verifyContractStatus: verifyInspection.status,
203
262
  verifyContractAction: verifyContract.action,
204
263
  lifecycleGate: workflowGate.lifecycleGate,
@@ -210,6 +269,7 @@ export async function runSddTest(projectRoot: string, options: RunSddTestOptions
210
269
  evidenceCoverage,
211
270
  policyJudgment,
212
271
  acceptanceCoverage,
272
+ capabilityEvidence,
213
273
  syncBackReady,
214
274
  commands,
215
275
  steps,
@@ -218,9 +278,6 @@ export async function runSddTest(projectRoot: string, options: RunSddTestOptions
218
278
  });
219
279
  const completedAt = new Date().toISOString();
220
280
  const evidence = [validationArtifact?.runRelativePath, indexArtifact.runRelativePath, ...steps.map((step) => step.outputArtifact)].filter((item): item is string => Boolean(item));
221
- const syncBackProposal = syncBackReady
222
- ? await writeTestSyncBackProposal(projectRoot, state.runId, options.taskId, evidence, acceptanceCoverage)
223
- : null;
224
281
 
225
282
  await recordRuntimeTestRun(projectRoot, {
226
283
  testRunId,
@@ -230,7 +287,7 @@ export async function runSddTest(projectRoot: string, options: RunSddTestOptions
230
287
  status,
231
288
  startedAt,
232
289
  completedAt,
233
- payload: { verifyContractStatus: verifyInspection.status, verifyContractAction: verifyContract.action, lifecycleGate: workflowGate.lifecycleGate, lifecycleProfile: workflowGate.lifecycleProfile, approvalPolicy: workflowGate.approvalPolicy, requiredStages: workflowGate.requiredStages, primaryReason: workflowGate.primaryReason, commandStatus, evidenceCoverage, policyJudgment, acceptanceCoverage, syncBackReady, commands, commandInputs, evidence, gaps, syncBackProposal: syncBackProposal?.path ?? null }
290
+ payload: { verifyContractStatus: verifyInspection.status, verifyContractAction: verifyContract.action, lifecycleGate: workflowGate.lifecycleGate, lifecycleProfile: workflowGate.lifecycleProfile, approvalPolicy: workflowGate.approvalPolicy, requiredStages: workflowGate.requiredStages, primaryReason: workflowGate.primaryReason, commandStatus, evidenceCoverage, policyJudgment, validationStatus, workflowGateStatus: gateDecision.status, runtimeJudgment, workflowGateDecision: gateDecision, acceptanceCoverage, capabilityEvidence, syncBackReady, commands, commandInputs, evidence, gaps }
234
291
  });
235
292
  await recordRuntimeProjection(projectRoot, 'test_runtime', `${context.partition}:${options.taskId}:${state.runId}`, {
236
293
  contract: 'sdd-test-runtime-v1',
@@ -238,6 +295,9 @@ export async function runSddTest(projectRoot: string, options: RunSddTestOptions
238
295
  runId: state.runId,
239
296
  taskId: options.taskId,
240
297
  status,
298
+ validationStatus,
299
+ workflowGateStatus: gateDecision.status,
300
+ runtimeJudgment,
241
301
  lifecycleGate: workflowGate.lifecycleGate,
242
302
  primaryReason: workflowGate.primaryReason,
243
303
  evidence,
@@ -253,21 +313,52 @@ export async function runSddTest(projectRoot: string, options: RunSddTestOptions
253
313
  gaps,
254
314
  riskDecision: orchestration.riskDecision
255
315
  });
256
- await persistTestRunState(projectRoot, state, options.taskId, status, commands, evidence, validationArtifact?.runRelativePath ?? null, syncBackProposal);
316
+ await persistTestGateOutcome(projectRoot, state.runId, options.taskId, status, validationStatus, commands, evidence, validationArtifact?.runRelativePath ?? null, gateDecision);
317
+ if (ownsValidationWave) {
318
+ await recordRuntimeValidationWaveRun(projectRoot, {
319
+ waveRunId: validationWaveRunId,
320
+ partition: context.partition,
321
+ runId: state.runId,
322
+ taskIds: validationWaveTaskIds,
323
+ status,
324
+ environmentSessionId: validationEnvironmentSessionId,
325
+ startedAt,
326
+ completedAt,
327
+ payload: { contract: 'phase-8.17-validation-wave-runtime-v1', mode: 'single-task', taskId: options.taskId, testRunId, evidence, gaps, workflowGateDecision: gateDecision }
328
+ });
329
+ await recordRuntimeValidationEnvironmentSession(projectRoot, {
330
+ sessionId: validationEnvironmentSessionId,
331
+ partition: context.partition,
332
+ runId: state.runId,
333
+ waveRunId: validationWaveRunId,
334
+ status: status === 'PASS' ? 'completed' : status === 'FAIL' ? 'failed' : 'blocked',
335
+ reuseKey: `${context.partition}:${options.taskId}`,
336
+ createdAt: startedAt,
337
+ updatedAt: completedAt,
338
+ payload: { contract: 'phase-8.17-validation-wave-runtime-v1', mode: 'single-task', taskId: options.taskId, validationStatus, workflowGateStatus: gateDecision.status, status }
339
+ });
340
+ }
341
+
257
342
  await appendEvent(projectRoot, state.runId, {
258
- event: status === 'PASS' ? 'test_runtime_passed' : 'test_runtime_failed',
343
+ event: status === 'PASS' ? 'test_runtime_passed' : 'test_runtime_blocked',
259
344
  runId: state.runId,
260
345
  summary: `SDD test runtime ${status} for ${options.taskId}`,
261
- data: { taskId: options.taskId, testRunId, status, evidence, gaps }
346
+ data: { taskId: options.taskId, testRunId, status, validationStatus, evidence, gaps, gateDecisionId: gateDecision.decisionId, gateStatus: gateDecision.status }
262
347
  });
263
348
 
264
349
  return {
265
350
  contract: 'sdd-test-runtime-v1',
266
351
  runId: state.runId,
267
352
  testRunId,
353
+ validationWaveRunId,
354
+ validationEnvironmentSessionId,
268
355
  branch: context.partition,
269
356
  taskId: options.taskId,
270
357
  status,
358
+ validationStatus,
359
+ workflowGateStatus: gateDecision.status,
360
+ runtimeJudgment,
361
+ workflowGateDecision: gateDecision,
271
362
  verifyContractStatus: verifyInspection.status,
272
363
  verifyContractAction: verifyContract.action,
273
364
  lifecycleGate: workflowGate.lifecycleGate,
@@ -279,16 +370,37 @@ export async function runSddTest(projectRoot: string, options: RunSddTestOptions
279
370
  evidenceCoverage,
280
371
  policyJudgment,
281
372
  acceptanceCoverage,
373
+ capabilityEvidence,
282
374
  syncBackReady,
283
375
  commands,
284
376
  steps,
285
377
  validationArtifact: validationArtifact?.runRelativePath ?? null,
286
378
  indexArtifact: indexArtifact.runRelativePath,
287
379
  gaps,
288
- next: nextForTestResult(status, context.partition, options.taskId, state.runId, indexArtifact.runRelativePath, workflowGate.nextAction)
380
+ next: nextForTestResult(status, runtimeJudgment, context.partition, options.taskId, state.runId, indexArtifact.runRelativePath, workflowGate.nextAction, gateDecision)
289
381
  };
290
382
  }
291
383
 
384
+ async function recordAcceptanceEvidenceMaps(projectRoot: string, waveRunId: string, testRunId: string, partition: string, runId: string, taskId: string, acceptanceCoverage: AcceptanceEvidenceCoverage[]): Promise<void> {
385
+ const createdAt = new Date().toISOString();
386
+ for (const coverage of acceptanceCoverage) {
387
+ await recordRuntimeAcceptanceEvidenceMap(projectRoot, {
388
+ mapId: runtimeScopedId(waveRunId, testRunId, taskId, coverage.acceptanceRef),
389
+ waveRunId,
390
+ testRunId,
391
+ partition,
392
+ runId,
393
+ taskId,
394
+ acceptanceRef: coverage.acceptanceRef,
395
+ status: coverage.status,
396
+ evidenceRefs: coverage.evidenceRefs.map((ref) => ref.ref),
397
+ gaps: coverage.gaps,
398
+ createdAt,
399
+ payload: coverage
400
+ });
401
+ }
402
+ }
403
+
292
404
  async function recordTestWorkflowProjection(projectRoot: string, input: { taskId: string; stageRun: StageRun; status: SddTestStatus; completedAt: string; evidence: string[]; gaps: string[]; riskDecision: LifecycleRiskDecision }): Promise<void> {
293
405
  const outputRefs = input.evidence.map((ref) => ({ kind: 'artifact' as const, ref }));
294
406
  const completedStage: StageRun = {
@@ -324,20 +436,8 @@ async function recordTestWorkflowProjection(projectRoot: string, input: { taskId
324
436
 
325
437
 
326
438
  async function ensureVerifyContractForTest(projectRoot: string, branch: string): Promise<{ inspection: VerifyContractInspection; action: VerifyContractAction }> {
327
- let inspection = await inspectVerifyContract(projectRoot, { branch, branchSource: 'cli_option' });
328
- if (inspection.status === 'BLOCKED') {
329
- return { inspection, action: 'blocked' };
330
- }
331
- if (inspection.status === 'PASS') {
332
- return { inspection, action: 'none' };
333
- }
334
-
335
- const written = await writeVerifyContract(projectRoot, { branch, branchSource: 'cli_option', force: inspection.exists });
336
- inspection = await inspectVerifyContract(projectRoot, { branch, branchSource: 'cli_option' });
337
- if (inspection.status !== 'PASS') {
338
- return { inspection, action: 'blocked' };
339
- }
340
- return { inspection, action: written.status === 'created' ? 'created' : 'refreshed' };
439
+ const inspection = await inspectVerifyContract(projectRoot, { branch, branchSource: 'cli_option' });
440
+ return { inspection, action: inspection.status === 'PASS' ? 'none' : 'blocked' };
341
441
  }
342
442
 
343
443
  function verifyContractBlocker(inspection: VerifyContractInspection): string {
@@ -369,8 +469,14 @@ export function renderSddTestResult(result: SddTestResult): string {
369
469
  '',
370
470
  resultSentenceForTest(result),
371
471
  '',
472
+ 'Decision:',
473
+ `- validation_status=${result.validationStatus}`,
474
+ `- workflow_gate_status=${result.workflowGateStatus}`,
475
+ `- workflow_gate_decision=${result.workflowGateDecision.decisionId}`,
476
+ '',
372
477
  'Why:',
373
478
  `- ${result.primaryReason}`,
479
+ `- capability_evidence=${capabilityEvidenceSummary(result.capabilityEvidence)}`,
374
480
  '',
375
481
  'Next:',
376
482
  `- ${result.next}`
@@ -485,31 +591,61 @@ function executeCommand(projectRoot: string, commandInput: NormalizedSddTestComm
485
591
  });
486
592
  }
487
593
 
488
- async function writeValidationArtifact(projectRoot: string, runId: string, task: SddTask, status: SddTestStatus, steps: SddTestCommandStep[], gaps: string[]): Promise<{ absolutePath: string; runRelativePath: string }> {
489
- const artifactPath = `validation-${task.id}.md`;
594
+ async function writeValidationArtifact(projectRoot: string, runId: string, task: SddTask, status: SddTestStatus, steps: SddTestCommandStep[], gaps: string[], capabilityEvidence: CapabilityEvidenceClassification[]): Promise<{ absolutePath: string; runRelativePath: string }> {
595
+ const artifactPath = `test-validation-${task.id}.md`;
490
596
  const runRelativePath = `artifacts/${artifactPath}`;
491
597
  const resultStatus = status === 'PASS' ? 'PASS' : status === 'FAIL' ? 'FAIL' : 'BLOCKED';
492
- const content = `# Validation ${task.id}\n\n\`\`\`sdd-result\ncontract: ${SDD_RESULT_CONTRACT}\nversion: ${SDD_RESULT_VERSION}\nagent: validator\ntask: ${task.id}\nstatus: ${resultStatus}\nartifacts:\n - ${runRelativePath}\n\`\`\`\n\n## Test Runtime\n\n- status: ${status}\n- commands:\n${steps.length > 0 ? steps.map((step) => ` - [${step.status}] ${step.command}`).join('\n') : ' - none'}\n- gaps:\n${gaps.length > 0 ? gaps.map((gap) => ` - ${gap}`).join('\n') : ' - none'}\n\n## Acceptance Evidence\n\n${renderEvidenceBlocks(task, status, runRelativePath, steps)}\n`;
598
+ const content = `# Test Validation ${task.id}\n\n\`\`\`sdd-result\ncontract: ${SDD_RESULT_CONTRACT}\nversion: ${SDD_RESULT_VERSION}\nagent: validator\ntask: ${task.id}\nstatus: ${resultStatus}\nartifacts:\n - ${runRelativePath}\n\`\`\`\n\n## Test Runtime\n\n- status: ${status}\n- commands:\n${steps.length > 0 ? steps.map((step) => ` - [${step.status}] ${step.command}`).join('\n') : ' - none'}\n- gaps:\n${gaps.length > 0 ? gaps.map((gap) => ` - ${gap}`).join('\n') : ' - none'}\n\n## Capability Evidence Classification\n\n${renderCapabilityEvidenceClassification(capabilityEvidence)}\n\n## Acceptance Evidence\n\n${renderEvidenceBlocks(task, status, runRelativePath, steps)}\n`;
493
599
  return writeArtifact(projectRoot, runId, artifactPath, content);
494
600
  }
495
601
 
496
- async function writeTestSyncBackProposal(projectRoot: string, runId: string, taskId: string, artifacts: string[], acceptanceCoverage: AcceptanceEvidenceCoverage[]): Promise<TestSyncBackProposal> {
497
- const content = `# Sync-back Proposal\n\n## ${taskId}\n\n- status: verified\n- summary: /sdd:test passed with complete command and acceptance evidence.\n- artifacts:\n${artifacts.length > 0 ? artifacts.map((artifact) => ` - ${artifact}`).join('\n') : ' - none'}\n- acceptance_coverage:\n${acceptanceCoverage.length > 0 ? acceptanceCoverage.map((coverage) => ` - [${coverage.status}] ${coverage.acceptanceRef}`).join('\n') : ' - none'}\n- gaps:\n - none\n\n## Boundaries\n\n- Proposal only; tasks.md/spec.md/plan.md were not modified by runtime.\n- /sdd:test executed declared validation commands and mapped evidence to acceptance refs.\n`;
498
- const written = await writeArtifact(projectRoot, runId, 'sync-back-proposal.md', content);
499
- return { path: written.runRelativePath, digest: hashDocumentContent(content) };
500
- }
501
602
 
502
603
  async function writeIndexArtifact(projectRoot: string, runId: string, payload: Omit<SddTestResult, 'contract' | 'runId' | 'indexArtifact' | 'next'>): Promise<{ absolutePath: string; runRelativePath: string }> {
503
604
  return writeArtifact(projectRoot, runId, `test-index-${payload.taskId}.json`, `${JSON.stringify({ contract: 'sdd-test-runtime-v1', runId, ...payload }, null, 2)}\n`);
504
605
  }
505
606
 
506
- async function persistTestRunState(projectRoot: string, state: RunState, taskId: string, status: SddTestStatus, commands: string[], evidence: string[], validationArtifact: string | null, syncBackProposal: TestSyncBackProposal | null): Promise<void> {
607
+ async function persistTestRunState(projectRoot: string, state: RunState, taskId: string, validationStatus: SddTestStatus, commands: string[], evidence: string[], validationArtifact: string | null): Promise<void> {
507
608
  const latest = await readRunState(projectRoot, state.runId);
508
609
  const knownArtifacts = new Set(latest.artifacts.map((artifact) => artifact.path));
509
610
  const now = new Date().toISOString();
510
611
  const nextArtifacts = evidence
511
612
  .filter((artifactPath) => !knownArtifacts.has(artifactPath))
512
- .map((artifactPath) => ({ path: artifactPath, kind: artifactPath.includes('validation-') ? 'validation' : 'test', task: taskId, agent: artifactPath === validationArtifact ? 'validator' : 'test-runtime', createdAt: now }));
613
+ .map((artifactPath) => ({ path: artifactPath, kind: testArtifactKind(artifactPath), task: taskId, agent: 'test-runtime', createdAt: now }));
614
+ const existingTaskState = latest.tasks[taskId];
615
+ await writeRunState(projectRoot, {
616
+ ...latest,
617
+ status: validationStatus === 'PASS' ? 'running' : validationStatus === 'FAIL' ? 'failed' : 'blocked',
618
+ phase: 'test',
619
+ currentTask: taskId,
620
+ tasks: {
621
+ ...latest.tasks,
622
+ [taskId]: {
623
+ ...baseRuntimeTaskState(existingTaskState),
624
+ status: validationStatus === 'PASS' ? 'validation_passed_pending_gate' : validationStatus === 'FAIL' ? 'validation_failed' : 'validation_blocked',
625
+ implementationStatus: existingTaskState?.implementationStatus ?? 'implemented',
626
+ verificationStatus: verificationStatusFromTest(validationStatus),
627
+ testStatus: validationStatus,
628
+ evidence
629
+ }
630
+ },
631
+ artifacts: [...latest.artifacts, ...nextArtifacts],
632
+ validation: {
633
+ status: validationStatus === 'PASS' ? 'pass' : validationStatus === 'FAIL' ? 'fail' : 'blocked',
634
+ commands,
635
+ evidence
636
+ },
637
+ syncBack: latest.syncBack
638
+ });
639
+ }
640
+
641
+ async function persistTestGateOutcome(projectRoot: string, runId: string, taskId: string, status: SddTestStatus, validationStatus: SddTestStatus, commands: string[], evidence: string[], validationArtifact: string | null, gateDecision: WorkflowGateDecision): Promise<void> {
642
+ const latest = await readRunState(projectRoot, runId);
643
+ const knownArtifacts = new Set(latest.artifacts.map((artifact) => artifact.path));
644
+ const now = new Date().toISOString();
645
+ const nextArtifacts = evidence
646
+ .filter((artifactPath) => !knownArtifacts.has(artifactPath))
647
+ .map((artifactPath) => ({ path: artifactPath, kind: testArtifactKind(artifactPath), task: taskId, agent: 'test-runtime', createdAt: now }));
648
+ const existingTaskState = latest.tasks[taskId];
513
649
  await writeRunState(projectRoot, {
514
650
  ...latest,
515
651
  status: status === 'PASS' ? 'completed' : status === 'FAIL' ? 'failed' : 'blocked',
@@ -518,29 +654,72 @@ async function persistTestRunState(projectRoot: string, state: RunState, taskId:
518
654
  tasks: {
519
655
  ...latest.tasks,
520
656
  [taskId]: {
521
- status: status === 'PASS' ? 'tested' : 'blocked',
657
+ ...baseRuntimeTaskState(existingTaskState),
658
+ status: runtimeTaskStatusAfterGate(status, validationStatus),
659
+ implementationStatus: existingTaskState?.implementationStatus ?? 'implemented',
660
+ verificationStatus: verificationStatusFromTest(validationStatus),
522
661
  testStatus: status,
662
+ validationStatus,
663
+ workflowGateStatus: gateDecision.status,
664
+ workflowGateDecisionId: gateDecision.decisionId,
523
665
  evidence
524
666
  }
525
667
  },
526
668
  artifacts: [...latest.artifacts, ...nextArtifacts],
527
669
  validation: {
528
- status: status === 'PASS' ? 'pass' : status === 'FAIL' ? 'fail' : 'blocked',
670
+ status: validationStatus === 'PASS' ? 'pass' : validationStatus === 'FAIL' ? 'fail' : 'blocked',
529
671
  commands,
530
672
  evidence
531
673
  },
532
- syncBack: syncBackProposal
533
- ? {
534
- mode: 'proposal',
535
- proposalPath: syncBackProposal.path,
536
- proposalDigest: syncBackProposal.digest,
537
- sourceVerifyStatus: status,
538
- status: 'proposed'
539
- }
540
- : latest.syncBack
674
+ syncBack: latest.syncBack
541
675
  });
542
676
  }
543
677
 
678
+ function testArtifactKind(artifactPath: string): string {
679
+ const fileName = artifactPath.split('/').pop() ?? artifactPath;
680
+ if (fileName.startsWith('test-validation-')) {
681
+ return 'test-validation';
682
+ }
683
+ if (fileName.startsWith('test-index-')) {
684
+ return 'test-index';
685
+ }
686
+ return 'test';
687
+ }
688
+
689
+ function baseRuntimeTaskState(existing: RunStateTaskRuntime | undefined): RunStateTaskRuntime {
690
+ return {
691
+ status: existing?.status ?? 'not_started',
692
+ implementationStatus: existing?.implementationStatus ?? 'not_started',
693
+ verificationStatus: existing?.verificationStatus ?? 'not_run',
694
+ validationBatch: existing?.validationBatch ?? null,
695
+ validationTiming: existing?.validationTiming ?? 'task_end',
696
+ requiresVerifyBeforeNext: existing?.requiresVerifyBeforeNext ?? true,
697
+ gaps: existing?.gaps,
698
+ artifacts: existing?.artifacts,
699
+ testStatus: existing?.testStatus,
700
+ workflowGateStatus: existing?.workflowGateStatus,
701
+ workflowGateDecisionId: existing?.workflowGateDecisionId,
702
+ evidence: existing?.evidence
703
+ };
704
+ }
705
+
706
+ function verificationStatusFromTest(validationStatus: SddTestStatus): RunStateTaskRuntime['verificationStatus'] {
707
+ if (validationStatus === 'PASS') {
708
+ return 'pass';
709
+ }
710
+ return validationStatus === 'FAIL' ? 'failed' : 'blocked';
711
+ }
712
+
713
+ function runtimeTaskStatusAfterGate(status: SddTestStatus, validationStatus: SddTestStatus): string {
714
+ if (status === 'PASS') {
715
+ return 'implemented_verified';
716
+ }
717
+ if (validationStatus === 'PASS') {
718
+ return 'workflow_gate_blocked';
719
+ }
720
+ return validationStatus === 'FAIL' ? 'validation_failed' : 'validation_blocked';
721
+ }
722
+
544
723
  function deriveCommandStatus(gaps: string[], steps: SddTestCommandStep[]): TestEvidenceStatus {
545
724
  if (gaps.length > 0 || steps.some((step) => step.status === 'blocked')) {
546
725
  return 'BLOCKED';
@@ -551,8 +730,8 @@ function deriveCommandStatus(gaps: string[], steps: SddTestCommandStep[]): TestE
551
730
  return 'PASS';
552
731
  }
553
732
 
554
- function buildAcceptanceCoverage(task: SddTask | null, steps: SddTestCommandStep[], commandStatus: TestEvidenceStatus): AcceptanceEvidenceCoverage[] {
555
- const acceptanceRefs = task ? taskAcceptanceRefs(task) : [];
733
+ function buildAcceptanceCoverage(task: SddTask | null, steps: SddTestCommandStep[], commandStatus: TestEvidenceStatus, acceptanceRefsOverride: string[] | undefined): AcceptanceEvidenceCoverage[] {
734
+ const acceptanceRefs = acceptanceRefsOverride && acceptanceRefsOverride.length > 0 ? [...new Set(acceptanceRefsOverride)] : task ? taskAcceptanceRefs(task) : [];
556
735
  return acceptanceRefs.map((acceptanceRef) => {
557
736
  const mappedSteps = steps.filter((step) => step.acceptanceRefs.includes(acceptanceRef));
558
737
  const hasPassingEvidence = mappedSteps.some((step) => step.status === 'pass');
@@ -566,7 +745,7 @@ function buildAcceptanceCoverage(task: SddTask | null, steps: SddTestCommandStep
566
745
  acceptanceRef,
567
746
  status,
568
747
  evidenceRefs: mappedSteps.map((step) => ({ kind: 'artifact', ref: step.outputArtifact })),
569
- gaps: status === 'complete' ? [] : [`Acceptance ${acceptanceRef} has no complete non-stale evidence from /sdd:test.`]
748
+ gaps: status === 'complete' ? [] : [`Acceptance ${acceptanceRef} has no complete non-stale evidence from sdd test task.`]
570
749
  };
571
750
  });
572
751
  }
@@ -594,7 +773,72 @@ function derivePolicyJudgment(commandStatus: TestEvidenceStatus, evidenceCoverag
594
773
  return 'PASS';
595
774
  }
596
775
 
597
- function buildUnifiedTestEvidenceRun(id: string, branch: string, runId: string, taskId: string, commandStatus: TestEvidenceStatus, evidenceCoverage: EvidenceCoverageStatus, policyJudgment: TestEvidenceStatus, steps: SddTestCommandStep[], acceptanceCoverage: AcceptanceEvidenceCoverage[], syncBackReady: boolean, gaps: string[]): UnifiedTestEvidenceRun {
776
+ async function resolveTestRuntimeDurableGap(
777
+ projectRoot: string,
778
+ branch: string,
779
+ runId: string,
780
+ taskId: string,
781
+ validationStatus: SddTestStatus,
782
+ gaps: string[]
783
+ ): Promise<void> {
784
+ if (validationStatus !== 'PASS' || gaps.length > 0) {
785
+ return;
786
+ }
787
+ await updateRuntimeDurableGapStatus(projectRoot, {
788
+ gapId: testRuntimeGapId(branch, runId, taskId),
789
+ status: 'resolved',
790
+ source: 'gate_policy',
791
+ payload: { validationStatus, gaps }
792
+ });
793
+ }
794
+
795
+ async function recordTestRuntimeDurableGap(
796
+ projectRoot: string,
797
+ branch: string,
798
+ runId: string,
799
+ taskId: string,
800
+ status: SddTestStatus,
801
+ validationStatus: SddTestStatus,
802
+ runtimeJudgment: WorkflowGateStatus,
803
+ gaps: string[],
804
+ evidenceRefs: string[]
805
+ ): Promise<void> {
806
+ if (status === 'PASS' && gaps.length === 0) {
807
+ return;
808
+ }
809
+ const message = gaps[0] ?? (runtimeJudgment === 'PASS' ? `Validation status is ${validationStatus}.` : `Workflow gate status is ${runtimeJudgment}.`);
810
+ await recordRuntimeDurableGap(projectRoot, {
811
+ gapId: testRuntimeGapId(branch, runId, taskId),
812
+ partition: branch,
813
+ taskId,
814
+ runId,
815
+ stage: 'test',
816
+ gate: 'test',
817
+ source: 'runtime',
818
+ category: runtimeJudgment === 'PASS' ? 'validation' : 'workflow_gate',
819
+ severity: 'blocking',
820
+ status: 'open',
821
+ message,
822
+ recommendation: `Resolve test runtime gaps for ${taskId}, then rerun sdd test task ${taskId} --branch ${branch}.`,
823
+ evidenceRefs,
824
+ proposalRefs: [],
825
+ sourceRefs: [],
826
+ payload: { status, validationStatus, runtimeJudgment, gaps }
827
+ });
828
+ }
829
+
830
+ function testRuntimeGapId(branch: string, _runId: string, taskId: string): string {
831
+ return runtimeScopedId(branch, taskId, 'test-runtime-gap');
832
+ }
833
+
834
+ function finalStatusForTest(validationStatus: SddTestStatus, runtimeJudgment: WorkflowGateStatus): SddTestStatus {
835
+ if (validationStatus !== 'PASS') {
836
+ return validationStatus;
837
+ }
838
+ return runtimeJudgment === 'PASS' ? 'PASS' : 'BLOCKED';
839
+ }
840
+
841
+ function buildUnifiedTestEvidenceRun(id: string, branch: string, runId: string, taskId: string, commandStatus: TestEvidenceStatus, evidenceCoverage: EvidenceCoverageStatus, policyJudgment: TestEvidenceStatus, status: SddTestStatus, runtimeJudgment: WorkflowGateStatus, steps: SddTestCommandStep[], acceptanceCoverage: AcceptanceEvidenceCoverage[], capabilityEvidence: CapabilityEvidenceClassification[], syncBackReady: boolean, gaps: string[], gateNextAction: string | null, gateDecision: WorkflowGateDecision | null): UnifiedTestEvidenceRun {
598
842
  return {
599
843
  contract: TEST_EVIDENCE_RUN_CONTRACT_VERSION,
600
844
  id,
@@ -612,26 +856,104 @@ function buildUnifiedTestEvidenceRun(id: string, branch: string, runId: string,
612
856
  completedAt: new Date().toISOString()
613
857
  })),
614
858
  acceptanceCoverage,
859
+ capabilityEvidence,
615
860
  syncBackReady,
616
861
  gaps: [...gaps, ...acceptanceCoverage.flatMap((coverage) => coverage.gaps)],
617
- next: nextForTestResult(policyJudgment, branch, taskId, runId, `artifacts/test-index-${taskId}.json`, null),
862
+ next: nextForTestResult(status, runtimeJudgment, branch, taskId, runId, `artifacts/test-index-${taskId}.json`, gateNextAction, gateDecision),
618
863
  generatedAt: new Date().toISOString()
619
864
  };
620
865
  }
621
866
 
622
- function nextForTestResult(status: SddTestStatus, branch: string, taskId: string, runId: string, indexArtifact: string, gateNextAction: string | null): string {
867
+ function buildCapabilityEvidenceClassification(decision: AgentCapabilityRouteDecision | null, steps: SddTestCommandStep[]): CapabilityEvidenceClassification[] {
868
+ if (!decision) {
869
+ return [{
870
+ class: 'diagnostic',
871
+ source: 'runtime_diagnostic',
872
+ domainOrSourceId: 'capability-routing',
873
+ evidenceRefs: [],
874
+ acceptanceRefs: [],
875
+ provenanceRefs: [],
876
+ reason: 'Capability routing did not run; no capability output is accepted as test evidence.'
877
+ }];
878
+ }
879
+ const acceptanceRefs = [...new Set(steps.flatMap((step) => step.acceptanceRefs))];
880
+ const professionalEvidence = decision.selectedDomains.map((domain) => ({
881
+ class: 'candidate' as const,
882
+ source: 'professional_capability' as const,
883
+ domainOrSourceId: domain.domain,
884
+ evidenceRefs: [],
885
+ acceptanceRefs,
886
+ provenanceRefs: [{ kind: 'projection' as const, ref: `capability:${domain.capabilityId}` }],
887
+ reason: `${domain.reason}; capability output is advisory candidate evidence until accepted by command evidence and policy refs.`
888
+ }));
889
+ const externalEvidence = decision.rejectedExternalSources.map((source) => ({
890
+ class: capabilityClassForRejectedSource(source.quarantineStatus) as CapabilityEvidenceClassification['class'],
891
+ source: 'external_source' as const,
892
+ domainOrSourceId: source.sourceId,
893
+ evidenceRefs: [],
894
+ acceptanceRefs: [],
895
+ provenanceRefs: [{ kind: 'external' as const, ref: source.sourceId }],
896
+ reason: source.reason
897
+ }));
898
+ return [...professionalEvidence, ...externalEvidence];
899
+ }
900
+
901
+ function capabilityClassForRejectedSource(status: AgentCapabilityRouteDecision['rejectedExternalSources'][number]['quarantineStatus']): CapabilityEvidenceClassification['class'] {
902
+ if (status === 'denied') {
903
+ return 'blocked';
904
+ }
905
+ if (status === 'required' || status === 'quarantined') {
906
+ return 'quarantined';
907
+ }
908
+ return 'diagnostic';
909
+ }
910
+
911
+ function renderCapabilityEvidenceClassification(items: CapabilityEvidenceClassification[]): string {
912
+ if (items.length === 0) {
913
+ return '- none';
914
+ }
915
+ return items.map((item) => `- [${item.class}] ${item.source}:${item.domainOrSourceId} — ${item.reason}`).join('\n');
916
+ }
917
+
918
+ function capabilityEvidenceSummary(items: CapabilityEvidenceClassification[]): string {
919
+ if (items.length === 0) {
920
+ return 'none';
921
+ }
922
+ const counts = new Map<CapabilityEvidenceClassification['class'], number>();
923
+ for (const item of items) {
924
+ counts.set(item.class, (counts.get(item.class) ?? 0) + 1);
925
+ }
926
+ return [...counts.entries()].map(([kind, count]) => `${kind}:${count}`).join(',');
927
+ }
928
+
929
+ function nextForTestResult(status: SddTestStatus, runtimeJudgment: WorkflowGateStatus, branch: string, taskId: string, _runId: string, indexArtifact: string, gateNextAction: string | null, gateDecision: WorkflowGateDecision | null): string {
623
930
  if (status === 'PASS') {
624
- return `sdd sync-back inspect ${runId} --branch ${branch} --task ${taskId}`;
931
+ return `sdd ship --branch ${branch} --dry-run`;
932
+ }
933
+ if (gateNextAction) {
934
+ return gateNextAction;
935
+ }
936
+ if (runtimeJudgment === 'HUMAN_REQUIRED') {
937
+ return gateDecision ? `Create a decision card for workflow gate ${gateDecision.decisionId}, then rerun sdd test task ${taskId} --branch ${branch}.` : `Create a decision card, then rerun sdd test task ${taskId} --branch ${branch}.`;
625
938
  }
626
- return gateNextAction ?? `Inspect ${indexArtifact}, fix command/evidence gaps, then rerun sdd test task ${taskId} --branch ${branch}.`;
939
+ if (runtimeJudgment === 'WARN') {
940
+ return gateDecision ? `Review workflow gate ${gateDecision.decisionId} warnings, then rerun sdd test task ${taskId} --branch ${branch} or proceed only with explicit review.` : `Review workflow gate warnings, then rerun sdd test task ${taskId} --branch ${branch}.`;
941
+ }
942
+ if (runtimeJudgment === 'ADVISORY_ONLY') {
943
+ return `Inspect advisor assessments for ${taskId}; advisory output cannot satisfy the test gate.`;
944
+ }
945
+ if (status === 'FAIL') {
946
+ return `Inspect ${indexArtifact}, fix failing validation commands, then rerun sdd test task ${taskId} --branch ${branch}.`;
947
+ }
948
+ return gateDecision ? `Inspect ${indexArtifact} and workflow gate ${gateDecision.decisionId}, resolve blockers, then rerun sdd test task ${taskId} --branch ${branch}.` : `Inspect ${indexArtifact}, fix command/evidence gaps, then rerun sdd test task ${taskId} --branch ${branch}.`;
627
949
  }
628
950
 
629
951
  function resultSentenceForTest(result: SddTestResult): string {
630
- if (result.status === 'PASS' && result.lifecycleGate === 'direct') {
631
- return 'Validation passed and sync-back is ready.';
632
- }
633
952
  if (result.status === 'PASS') {
634
- return 'Validation passed; sync-back needs review.';
953
+ return 'Validation and workflow gate passed; proceed to release readiness.';
954
+ }
955
+ if (result.validationStatus === 'PASS' && result.workflowGateStatus !== 'PASS') {
956
+ return `Validation passed, but workflow gate returned ${result.workflowGateStatus}.`;
635
957
  }
636
958
  if (result.commandStatus === 'BLOCKED') {
637
959
  return 'Blocked before validation commands ran.';
@@ -677,7 +999,10 @@ function normalizeTestCommandInput(input: SddTestCommandInput): NormalizedSddTes
677
999
  throw new Error('Command input must include command or argv.');
678
1000
  }
679
1001
 
680
- function acceptanceRefsForCommand(task: SddTask | null, command: string): string[] {
1002
+ function acceptanceRefsForCommand(task: SddTask | null, command: string, acceptanceRefsOverride: string[] | undefined): string[] {
1003
+ if (acceptanceRefsOverride && acceptanceRefsOverride.length > 0) {
1004
+ return [...new Set(acceptanceRefsOverride)];
1005
+ }
681
1006
  return [...new Set((task?.validationCommands ?? [])
682
1007
  .filter((entry) => entry.command === command)
683
1008
  .flatMap((entry) => entry.acceptanceRefs))];