create-agdf 0.30.0 → 0.32.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 (366) hide show
  1. package/generated/.agdf/control/README.md +5 -0
  2. package/generated/.agdf/control/templates/BRAND.md +28 -0
  3. package/generated/.agdf/control/templates/artefacts/PRD.md +11 -0
  4. package/generated/.agdf/control/templates/artefacts/SD.md +4 -0
  5. package/generated/.agdf/control/templates/artefacts/UX_INTENT_DEFINITION.md +1 -1
  6. package/generated/.opencode/agdf-interaction-locales.json +436 -2
  7. package/generated/.opencode/contracts/gate-artifact-preparation.md +9 -3
  8. package/generated/.opencode/contracts/interaction.md +10 -4
  9. package/generated/.opencode/contracts/modes.md +5 -0
  10. package/generated/.opencode/contracts/prd-definition.md +40 -1
  11. package/generated/.opencode/contracts/quality.md +35 -0
  12. package/generated/.opencode/contracts/request-activation.md +6 -3
  13. package/generated/.opencode/contracts/sd-definition.md +46 -0
  14. package/generated/.opencode/contracts/tp-definition.md +8 -0
  15. package/generated/.opencode/contracts/ur-definition.md +9 -5
  16. package/generated/.opencode/skills/agdf-ux-intent-definition/SKILL.md +31 -2
  17. package/generated/plugins/agdf/.claude-plugin/plugin.json +1 -1
  18. package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
  19. package/generated/plugins/agdf/companion/events.mjs +119 -0
  20. package/generated/plugins/agdf/companion/figure.mjs +242 -111
  21. package/generated/plugins/agdf/companion/gate-bar.mjs +10 -28
  22. package/generated/plugins/agdf/companion/localization.mjs +15 -32
  23. package/generated/plugins/agdf/companion/notice.mjs +20 -10
  24. package/generated/plugins/agdf/companion/register.mjs +310 -66
  25. package/generated/plugins/agdf/companion/run-state.mjs +89 -90
  26. package/generated/plugins/agdf/companion/state.mjs +6 -32
  27. package/generated/plugins/agdf/companion/view.mjs +199 -24
  28. package/generated/plugins/agdf/control/README.md +5 -0
  29. package/generated/plugins/agdf/control/templates/BRAND.md +28 -0
  30. package/generated/plugins/agdf/control/templates/artefacts/PRD.md +11 -0
  31. package/generated/plugins/agdf/control/templates/artefacts/SD.md +4 -0
  32. package/generated/plugins/agdf/control/templates/artefacts/UX_INTENT_DEFINITION.md +1 -1
  33. package/generated/plugins/agdf/mcp/server/README.md +26 -2
  34. package/generated/plugins/agdf/mcp/server/package.json +3 -3
  35. package/generated/plugins/agdf/mcp/server/src/generation-runtime.js +14 -3
  36. package/generated/plugins/agdf/mcp/server/src/generation.js +8 -2
  37. package/generated/plugins/agdf/mcp/server/src/main.js +5 -1
  38. package/generated/plugins/agdf/mcp/server/src/next-action.js +227 -0
  39. package/generated/plugins/agdf/mcp/server/src/prepared-call-transport.js +306 -0
  40. package/generated/plugins/agdf/mcp/server/src/safe-read-continuation.js +62 -0
  41. package/generated/plugins/agdf/mcp/server/src/server.js +155 -37
  42. package/generated/plugins/agdf/mcp/server/ui/cockpit.html +130 -33
  43. package/generated/plugins/agdf/mcp/server/ui/decision-manifest.json +3 -3
  44. package/generated/plugins/agdf/mcp/server/ui/decision.html +3 -3
  45. package/generated/plugins/agdf/mcp/server/ui/manifest.json +3 -3
  46. package/generated/plugins/agdf/meta/agdf-interaction-locales.json +436 -2
  47. package/generated/plugins/agdf/meta/agdf-mcp-capability.json +1 -1
  48. package/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
  49. package/generated/plugins/agdf/meta/contracts/gate-artifact-preparation.md +9 -3
  50. package/generated/plugins/agdf/meta/contracts/interaction.md +10 -4
  51. package/generated/plugins/agdf/meta/contracts/modes.md +5 -0
  52. package/generated/plugins/agdf/meta/contracts/prd-definition.md +40 -1
  53. package/generated/plugins/agdf/meta/contracts/quality.md +35 -0
  54. package/generated/plugins/agdf/meta/contracts/request-activation.md +6 -3
  55. package/generated/plugins/agdf/meta/contracts/sd-definition.md +46 -0
  56. package/generated/plugins/agdf/meta/contracts/tp-definition.md +8 -0
  57. package/generated/plugins/agdf/meta/contracts/ur-definition.md +9 -5
  58. package/generated/plugins/agdf/meta/copilot-payload-baseline.json +3 -3
  59. package/generated/plugins/agdf/meta/distribution-profile-history.json +14 -0
  60. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-interaction-locales.json +436 -2
  61. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
  62. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/gate-artifact-preparation.md +9 -3
  63. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/interaction.md +10 -4
  64. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/modes.md +5 -0
  65. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/prd-definition.md +40 -1
  66. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/quality.md +35 -0
  67. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/request-activation.md +6 -3
  68. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/sd-definition.md +46 -0
  69. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/tp-definition.md +8 -0
  70. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/ur-definition.md +9 -5
  71. package/generated/plugins/agdf/runtime/create-agdf/lib/cli/command-registry.js +2 -1
  72. package/generated/plugins/agdf/runtime/create-agdf/lib/cli/parse-args.js +7 -4
  73. package/generated/plugins/agdf/runtime/create-agdf/lib/cli/project-read-command.js +29 -0
  74. package/generated/plugins/agdf/runtime/create-agdf/lib/cli/validation-handlers.js +2 -1
  75. package/generated/plugins/agdf/runtime/create-agdf/lib/mcp-dispatch-runtime.js +36 -7
  76. package/generated/plugins/agdf/runtime/create-agdf/lib/mcp-lifecycle/package.js +7 -0
  77. package/generated/plugins/agdf/runtime/create-agdf/lib/mcp-lifecycle/plugin-runtime.js +34 -6
  78. package/generated/plugins/agdf/runtime/create-agdf/lib/mcp-lifecycle/prepared-call-journal.js +269 -0
  79. package/generated/plugins/agdf/runtime/create-agdf/lib/mcp-worker-runtime.js +86 -83
  80. package/generated/plugins/agdf/runtime/create-agdf/lib/runtime/validator-application.js +2 -2
  81. package/generated/plugins/agdf/runtime/create-agdf/package.json +1 -1
  82. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/companion/events.js +157 -0
  83. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/companion/figure-state.js +38 -0
  84. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/companion/journal.js +186 -0
  85. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/companion/run-view.js +227 -0
  86. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/acceptance-criteria.js +2 -0
  87. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/closeout-readiness.js +24 -6
  88. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/decision-content-placeholder.js +4 -1
  89. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/gate-check.js +49 -7
  90. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/gate-policy-inputs.js +2 -0
  91. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/gate-policy-pure.js +7 -3
  92. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/prd-readiness.js +7 -2
  93. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/report-decision.js +9 -0
  94. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/traceability-readiness.js +57 -8
  95. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/ur-readiness.js +15 -2
  96. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/artifact-readiness.js +5 -3
  97. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/authoring-inputs.js +107 -22
  98. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/cockpit-list.js +10 -8
  99. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/cockpit-session.js +11 -3
  100. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/cockpit-work.js +4 -2
  101. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/cockpit.js +47 -33
  102. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/contract.js +64 -24
  103. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/material-recording-calls.js +54 -0
  104. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/project-state.js +2 -1
  105. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/run-classification.js +31 -0
  106. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/selection.js +6 -0
  107. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/service.js +32 -5
  108. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/work-situation.js +25 -0
  109. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-read/cockpit-worker.js +1 -0
  110. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/authoring-text-handoff.js +3 -0
  111. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/input-resolution.js +7 -5
  112. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/material-limits.js +4 -0
  113. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/prepared-control-calls.js +137 -0
  114. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/presentation-delivery.js +4 -1
  115. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-command-contract.js +10 -4
  116. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-command-schema.js +9 -3
  117. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-command-service.js +35 -11
  118. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-create-command.js +6 -1
  119. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-identity.js +2 -0
  120. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-inventory-reader.js +54 -5
  121. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-inventory.js +12 -27
  122. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-material.js +25 -7
  123. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-presentation-render.js +113 -28
  124. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-revision.js +38 -20
  125. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-source-revisions.js +37 -17
  126. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-state-reader.js +10 -3
  127. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-steps.js +8 -5
  128. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-title.js +43 -0
  129. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/index.js +3 -1
  130. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/interaction-catalog-validation.js +7 -1
  131. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/interaction-catalog.js +8 -0
  132. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/interaction-presentation.js +31 -10
  133. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/mcp-input-hints.js +30 -1
  134. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/mcp-tool-errors.js +5 -3
  135. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/resources/canonical-init-plan.js +1 -1
  136. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/runtime/plugin-provenance.js +9 -2
  137. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/contract.js +6 -4
  138. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/delivery-intake.js +3 -1
  139. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/mcp-continuation.js +25 -2
  140. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/prd-definition.js +3 -2
  141. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/readiness-findings.js +7 -0
  142. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/sd-definition.js +4 -2
  143. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/service.js +17 -4
  144. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/tp-definition.js +4 -2
  145. package/generated/plugins/agdf/runtime/runtime-manifest.json +2 -2
  146. package/generated/plugins/agdf/scripts/check-runtime-integrity.mjs +4 -3
  147. package/generated/plugins/agdf/skills/ux-intent-definition/SKILL.md +31 -2
  148. package/generated/plugins/agdf/skills/ux-intent-definition/help.md +8 -1
  149. package/generated/plugins/agdf/submission/openai/availability.md +1 -1
  150. package/generated/plugins/agdf/submission/openai/capability-matrix.json +1 -1
  151. package/generated/plugins/agdf/submission/openai/release-notes.md +5 -8
  152. package/generated/plugins/agdf/submission/openai/reviewer-cases.json +1 -1
  153. package/generated/plugins/agdf-planning/.codex-plugin/plugin.json +1 -1
  154. package/generated/plugins/agdf-planning/plugin.json +1 -1
  155. package/generated/plugins/copilot/agdf/.agdf-payload-inventory.json +358 -203
  156. package/generated/plugins/copilot/agdf/control/README.md +5 -0
  157. package/generated/plugins/copilot/agdf/control/templates/BRAND.md +28 -0
  158. package/generated/plugins/copilot/agdf/control/templates/artefacts/PRD.md +11 -0
  159. package/generated/plugins/copilot/agdf/control/templates/artefacts/SD.md +4 -0
  160. package/generated/plugins/copilot/agdf/control/templates/artefacts/UX_INTENT_DEFINITION.md +1 -1
  161. package/generated/plugins/copilot/agdf/mcp/server/README.md +26 -2
  162. package/generated/plugins/copilot/agdf/mcp/server/package.json +3 -3
  163. package/generated/plugins/copilot/agdf/mcp/server/src/generation-runtime.js +14 -3
  164. package/generated/plugins/copilot/agdf/mcp/server/src/generation.js +8 -2
  165. package/generated/plugins/copilot/agdf/mcp/server/src/main.js +5 -1
  166. package/generated/plugins/copilot/agdf/mcp/server/src/next-action.js +227 -0
  167. package/generated/plugins/copilot/agdf/mcp/server/src/prepared-call-transport.js +306 -0
  168. package/generated/plugins/copilot/agdf/mcp/server/src/safe-read-continuation.js +62 -0
  169. package/generated/plugins/copilot/agdf/mcp/server/src/server.js +155 -37
  170. package/generated/plugins/copilot/agdf/meta/agdf-plugin.definition.json +1 -1
  171. package/generated/plugins/copilot/agdf/meta/distribution-profile-history.json +14 -0
  172. package/generated/plugins/copilot/agdf/plugin.json +1 -1
  173. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-interaction-locales.json +436 -2
  174. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
  175. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/gate-artifact-preparation.md +9 -3
  176. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/interaction.md +10 -4
  177. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/modes.md +5 -0
  178. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/prd-definition.md +40 -1
  179. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/quality.md +35 -0
  180. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/request-activation.md +6 -3
  181. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/sd-definition.md +46 -0
  182. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/tp-definition.md +8 -0
  183. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/ur-definition.md +9 -5
  184. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/command-registry.js +2 -1
  185. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/parse-args.js +7 -4
  186. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/project-read-command.js +29 -0
  187. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/validation-handlers.js +2 -1
  188. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/mcp-dispatch-runtime.js +36 -7
  189. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/mcp-lifecycle/package.js +7 -0
  190. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/mcp-lifecycle/plugin-runtime.js +34 -6
  191. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/mcp-lifecycle/prepared-call-journal.js +269 -0
  192. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/mcp-worker-runtime.js +81 -78
  193. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/runtime/validator-application.js +2 -2
  194. package/generated/plugins/copilot/agdf/runtime/create-agdf/package.json +1 -1
  195. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/companion/events.js +157 -0
  196. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/companion/figure-state.js +38 -0
  197. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/companion/journal.js +186 -0
  198. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/companion/run-view.js +227 -0
  199. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/acceptance-criteria.js +2 -0
  200. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/closeout-readiness.js +24 -6
  201. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/decision-content-placeholder.js +4 -1
  202. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/gate-check.js +49 -7
  203. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/gate-policy-inputs.js +2 -0
  204. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/gate-policy-pure.js +7 -3
  205. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/prd-readiness.js +7 -2
  206. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/report-decision.js +9 -0
  207. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/traceability-readiness.js +57 -8
  208. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/ur-readiness.js +15 -2
  209. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/artifact-readiness.js +5 -3
  210. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/authoring-inputs.js +107 -22
  211. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/contract.js +64 -24
  212. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/material-recording-calls.js +54 -0
  213. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/project-state.js +2 -1
  214. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/run-classification.js +31 -0
  215. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/selection.js +6 -0
  216. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/service.js +32 -5
  217. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/work-situation.js +25 -0
  218. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/authoring-text-handoff.js +3 -0
  219. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/input-resolution.js +7 -5
  220. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/material-limits.js +4 -0
  221. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/prepared-control-calls.js +137 -0
  222. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/presentation-delivery.js +4 -1
  223. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-command-contract.js +10 -4
  224. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-command-schema.js +9 -3
  225. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-command-service.js +35 -11
  226. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-create-command.js +6 -1
  227. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-identity.js +2 -0
  228. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-inventory-reader.js +54 -5
  229. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-inventory.js +12 -27
  230. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-material.js +25 -7
  231. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-presentation-render.js +113 -28
  232. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-revision.js +38 -20
  233. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-source-revisions.js +37 -17
  234. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-state-reader.js +10 -3
  235. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-steps.js +8 -5
  236. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-title.js +43 -0
  237. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/index.js +3 -1
  238. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/interaction-catalog-validation.js +7 -1
  239. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/interaction-catalog.js +8 -0
  240. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/interaction-presentation.js +31 -10
  241. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/mcp-input-hints.js +30 -1
  242. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/mcp-tool-errors.js +5 -3
  243. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/resources/canonical-init-plan.js +1 -1
  244. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/runtime/plugin-provenance.js +9 -2
  245. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/contract.js +6 -4
  246. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/delivery-intake.js +3 -1
  247. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/mcp-continuation.js +25 -2
  248. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/prd-definition.js +3 -2
  249. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/readiness-findings.js +7 -0
  250. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/sd-definition.js +4 -2
  251. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/service.js +17 -4
  252. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/tp-definition.js +4 -2
  253. package/generated/plugins/copilot/agdf/runtime/runtime-manifest.json +2 -2
  254. package/generated/plugins/copilot/agdf/skills/agdf-interaction-locales.json +1 -1
  255. package/generated/plugins/copilot/agdf/skills/agdf-ux-intent-definition/SKILL.md +31 -2
  256. package/generated/plugins/copilot/agdf/skills/contracts/gate-artifact-preparation.md +9 -3
  257. package/generated/plugins/copilot/agdf/skills/contracts/interaction.md +10 -4
  258. package/generated/plugins/copilot/agdf/skills/contracts/modes.md +5 -0
  259. package/generated/plugins/copilot/agdf/skills/contracts/prd-definition.md +40 -1
  260. package/generated/plugins/copilot/agdf/skills/contracts/quality.md +35 -0
  261. package/generated/plugins/copilot/agdf/skills/contracts/request-activation.md +6 -3
  262. package/generated/plugins/copilot/agdf/skills/contracts/sd-definition.md +46 -0
  263. package/generated/plugins/copilot/agdf/skills/contracts/tp-definition.md +8 -0
  264. package/generated/plugins/copilot/agdf/skills/contracts/ur-definition.md +9 -5
  265. package/generated/submissions/openai/agdf/.codex-plugin/plugin.json +1 -1
  266. package/generated/submissions/openai/agdf/meta/agdf-interaction-locales.json +436 -2
  267. package/generated/submissions/openai/agdf/meta/agdf-plugin.definition.json +1 -1
  268. package/generated/submissions/openai/agdf/meta/contracts/gate-artifact-preparation.md +9 -3
  269. package/generated/submissions/openai/agdf/meta/contracts/interaction.md +10 -4
  270. package/generated/submissions/openai/agdf/meta/contracts/modes.md +5 -0
  271. package/generated/submissions/openai/agdf/meta/contracts/prd-definition.md +40 -1
  272. package/generated/submissions/openai/agdf/meta/contracts/quality.md +35 -0
  273. package/generated/submissions/openai/agdf/meta/contracts/request-activation.md +6 -3
  274. package/generated/submissions/openai/agdf/meta/contracts/sd-definition.md +46 -0
  275. package/generated/submissions/openai/agdf/meta/contracts/tp-definition.md +8 -0
  276. package/generated/submissions/openai/agdf/meta/contracts/ur-definition.md +9 -5
  277. package/generated/submissions/openai/agdf/meta/copilot-payload-baseline.json +3 -3
  278. package/generated/submissions/openai/agdf/meta/distribution-profile-history.json +14 -0
  279. package/generated/submissions/openai/agdf/plugin.json +1 -1
  280. package/generated/submissions/openai/agdf/skills/ux-intent-definition/SKILL.md +31 -2
  281. package/generated/submissions/openai/agdf/skills/ux-intent-definition/help.md +8 -1
  282. package/generated/submissions/openai/agdf/submission/openai/availability.md +1 -1
  283. package/generated/submissions/openai/agdf/submission/openai/capability-matrix.json +1 -1
  284. package/generated/submissions/openai/agdf/submission/openai/inventory.json +24 -24
  285. package/generated/submissions/openai/agdf/submission/openai/listing.json +1 -1
  286. package/generated/submissions/openai/agdf/submission/openai/readiness.json +2 -2
  287. package/generated/submissions/openai/agdf/submission/openai/readiness.md +2 -2
  288. package/generated/submissions/openai/agdf/submission/openai/release-notes.md +5 -8
  289. package/generated/submissions/openai/agdf/submission/openai/reviewer-cases.json +1 -1
  290. package/lib/cli/command-registry.js +2 -1
  291. package/lib/cli/parse-args.js +7 -4
  292. package/lib/cli/project-read-command.js +29 -0
  293. package/lib/cli/validation-handlers.js +2 -1
  294. package/lib/mcp-dispatch-runtime.js +36 -7
  295. package/lib/mcp-lifecycle/package.js +7 -0
  296. package/lib/mcp-lifecycle/plugin-runtime.js +34 -6
  297. package/lib/mcp-lifecycle/prepared-call-journal.js +269 -0
  298. package/lib/mcp-worker-runtime.js +86 -83
  299. package/lib/runtime/validator-application.js +2 -2
  300. package/lib/scaffold/plan.js +2 -0
  301. package/package.json +1 -1
  302. package/runtime/core/lib/companion/events.js +157 -0
  303. package/runtime/core/lib/companion/figure-state.js +38 -0
  304. package/runtime/core/lib/companion/journal.js +186 -0
  305. package/runtime/core/lib/companion/run-view.js +227 -0
  306. package/runtime/core/lib/control-evaluation/acceptance-criteria.js +2 -0
  307. package/runtime/core/lib/control-evaluation/closeout-readiness.js +24 -6
  308. package/runtime/core/lib/control-evaluation/decision-content-placeholder.js +4 -1
  309. package/runtime/core/lib/control-evaluation/gate-check.js +49 -7
  310. package/runtime/core/lib/control-evaluation/gate-policy-inputs.js +2 -0
  311. package/runtime/core/lib/control-evaluation/gate-policy-pure.js +7 -3
  312. package/runtime/core/lib/control-evaluation/prd-readiness.js +7 -2
  313. package/runtime/core/lib/control-evaluation/report-decision.js +9 -0
  314. package/runtime/core/lib/control-evaluation/traceability-readiness.js +57 -8
  315. package/runtime/core/lib/control-evaluation/ur-readiness.js +15 -2
  316. package/runtime/core/lib/control-inspect/artifact-readiness.js +5 -3
  317. package/runtime/core/lib/control-inspect/authoring-inputs.js +107 -22
  318. package/runtime/core/lib/control-inspect/cockpit-list.js +10 -8
  319. package/runtime/core/lib/control-inspect/cockpit-session.js +11 -3
  320. package/runtime/core/lib/control-inspect/cockpit-work.js +4 -2
  321. package/runtime/core/lib/control-inspect/cockpit.js +47 -33
  322. package/runtime/core/lib/control-inspect/contract.js +64 -24
  323. package/runtime/core/lib/control-inspect/material-recording-calls.js +54 -0
  324. package/runtime/core/lib/control-inspect/project-state.js +2 -1
  325. package/runtime/core/lib/control-inspect/run-classification.js +31 -0
  326. package/runtime/core/lib/control-inspect/selection.js +6 -0
  327. package/runtime/core/lib/control-inspect/service.js +32 -5
  328. package/runtime/core/lib/control-inspect/work-situation.js +25 -0
  329. package/runtime/core/lib/control-read/cockpit-worker.js +1 -0
  330. package/runtime/core/lib/control-state/authoring-text-handoff.js +3 -0
  331. package/runtime/core/lib/control-state/input-resolution.js +7 -5
  332. package/runtime/core/lib/control-state/material-limits.js +4 -0
  333. package/runtime/core/lib/control-state/prepared-control-calls.js +137 -0
  334. package/runtime/core/lib/control-state/presentation-delivery.js +4 -1
  335. package/runtime/core/lib/control-state/run-command-contract.js +10 -4
  336. package/runtime/core/lib/control-state/run-command-schema.js +9 -3
  337. package/runtime/core/lib/control-state/run-command-service.js +35 -11
  338. package/runtime/core/lib/control-state/run-create-command.js +6 -1
  339. package/runtime/core/lib/control-state/run-identity.js +2 -0
  340. package/runtime/core/lib/control-state/run-inventory-reader.js +54 -5
  341. package/runtime/core/lib/control-state/run-inventory.js +12 -27
  342. package/runtime/core/lib/control-state/run-material.js +25 -7
  343. package/runtime/core/lib/control-state/run-presentation-render.js +113 -28
  344. package/runtime/core/lib/control-state/run-revision.js +38 -20
  345. package/runtime/core/lib/control-state/run-source-revisions.js +37 -17
  346. package/runtime/core/lib/control-state/run-state-reader.js +10 -3
  347. package/runtime/core/lib/control-state/run-steps.js +8 -5
  348. package/runtime/core/lib/control-state/run-title.js +43 -0
  349. package/runtime/core/lib/index.js +3 -1
  350. package/runtime/core/lib/interaction-catalog-validation.js +7 -1
  351. package/runtime/core/lib/interaction-catalog.js +8 -0
  352. package/runtime/core/lib/interaction-presentation.js +31 -10
  353. package/runtime/core/lib/mcp-input-hints.js +30 -1
  354. package/runtime/core/lib/mcp-tool-errors.js +5 -3
  355. package/runtime/core/lib/resources/canonical-init-plan.js +1 -1
  356. package/runtime/core/lib/runtime/plugin-provenance.js +9 -2
  357. package/runtime/core/lib/skill-dispatch/contract.js +6 -4
  358. package/runtime/core/lib/skill-dispatch/delivery-intake.js +3 -1
  359. package/runtime/core/lib/skill-dispatch/mcp-continuation.js +25 -2
  360. package/runtime/core/lib/skill-dispatch/prd-definition.js +3 -2
  361. package/runtime/core/lib/skill-dispatch/readiness-findings.js +7 -0
  362. package/runtime/core/lib/skill-dispatch/sd-definition.js +4 -2
  363. package/runtime/core/lib/skill-dispatch/service.js +17 -4
  364. package/runtime/core/lib/skill-dispatch/tp-definition.js +4 -2
  365. package/generated/plugins/agdf/companion/core.mjs +0 -16
  366. package/generated/plugins/agdf/companion/locales.json +0 -200
@@ -0,0 +1,227 @@
1
+ // Companion run view (SD SDD-001, SDD-002): a read-only projection of the unchanged gate-check
2
+ // report of each run, beside the run inventory of one project root. It never re-derives a gate
3
+ // rule: status fields are copied from the status card verbatim, so every consumer of the run
4
+ // view sees exactly what the status card shows. Nothing here writes or authorizes.
5
+ import { existsSync, realpathSync } from 'node:fs';
6
+ import { join } from 'node:path';
7
+ import { readFileSync, statSync } from '../control-read/fs.js';
8
+ import { captureControlScope } from '../control-read/snapshot.js';
9
+ import { containedRegularFile, hasSymlinkComponent, isSafeControlRelativePath } from '../control-state/contained-file.js';
10
+ import { parseControlState } from '../control-state/run-state-parser.js';
11
+ import { runIdentity } from '../control-state/run-title.js';
12
+ import { localizedDecisionFields } from '../control-evaluation/decision-content-readiness.js';
13
+ import { evaluateGateCheck } from '../control-evaluation/gate-check.js';
14
+ import { readRunInventory } from '../control-state/run-inventory-reader.js';
15
+ import { runFolderEntries } from '../control-state/run-state-reader.js';
16
+ import { readArtefactBindings } from '../control-state/artefact-bindings.js';
17
+ import { readEvidenceBindings } from '../control-state/evidence-bindings.js';
18
+ import { runRelativePath } from '../control-state/run-identity.js';
19
+ import { artefactFileDigest } from '../control-state/run-seal-compute.js';
20
+ import { boundedCode } from '../control-inspect/run-classification.js';
21
+ import { localizeBlockingCondition, localizeOperationalValue } from '../interaction-presentation.js';
22
+ import { interactionLocales, resolveArtifactPresentationLanguages } from '../resources/context.js';
23
+ import { deriveFigureState } from './figure-state.js';
24
+
25
+ export const RUN_VIEW_SCHEMA = 'run-view/1';
26
+ export const DIAGNOSIS_REASONS = Object.freeze(['run_version_unsupported', 'run_state_invalid', 'too_large', 'missing']);
27
+ // The reader's findings for a run folder without a readable run state: the path finding of
28
+ // run-state-reader.js (invalidRun) and the inventory's finding for a run without text (run-inventory.js).
29
+ const MISSING_CODES = new Set(['AGDF_RUN_PATH_INVALID', 'AGDF_RUN_STATE_UNAVAILABLE']);
30
+ // The classifications run-state-resolver.js treats as unsupported (AGDF_RUN_VERSION_UNSUPPORTED).
31
+ const UNSUPPORTED_CLASSIFICATIONS = new Set(['unsupported_version', 'unsupported_layout']);
32
+
33
+ // Per-run reason of an unreadable run (SD SDD-003) from the reader findings: unsupported by their
34
+ // classification, as run-state-resolver.js and the cockpit decide it (CR finding CIR-03), missing
35
+ // when only the missing-state findings are present, otherwise invalid. Core reports no size bound
36
+ // of its own, so an oversized run state is reported with the reason Core gives it; too_large stays
37
+ // reserved for such a bound (contradiction C1).
38
+ export function diagnosisReason(findings) {
39
+ if (findings.some(finding => UNSUPPORTED_CLASSIFICATIONS.has(finding.classification))) return 'run_version_unsupported';
40
+ if (findings.length && findings.every(finding => MISSING_CODES.has(finding.code))) return 'missing';
41
+ return 'run_state_invalid';
42
+ }
43
+
44
+ export function projectDiagnosis(entries) {
45
+ const unreadable = entries.filter(entry => !entry.valid).map(entry => ({ run_id: entry.run_id, reason: entry.unreadable_reason ?? 'run_state_invalid', codes: entry.findings }));
46
+ const by_reason = Object.fromEntries(DIAGNOSIS_REASONS.map(reason => [reason, unreadable.filter(row => row.reason === reason).length]));
47
+ return { unreadable, counts: { unreadable: unreadable.length, readable: entries.length - unreadable.length, by_reason } };
48
+ }
49
+
50
+ const NAMING_TEXT_LIMIT = 500;
51
+ const UR_READ_LIMIT = 131072;
52
+ const bounded = value => (typeof value === 'string' && value.length > NAMING_TEXT_LIMIT ? `${value.slice(0, NAMING_TEXT_LIMIT - 1)}…` : value);
53
+
54
+ // How a run names itself to a person, read inside the run's own snapshot: the stable title of the
55
+ // shared Run title rule (registered UR heading, then the authored Objective; a bare Run ID is no
56
+ // title) and the goal in the display language. Where display and artefact language differ, the goal
57
+ // is the one the UR's localized approval summary states. An unreadable UR leaves both to the Run document.
58
+ export function readRunNaming(root, runId, language = 'en') {
59
+ let content;
60
+ try { content = readFileSync(join(root, runRelativePath(runId, '', 'RUN_STATE.md')), 'utf8'); } catch { return null; }
61
+ let urHeading = '', localizedGoal = null;
62
+ try {
63
+ const path = String(parseControlState(content).artefacts.get('UR')?.path ?? '').replace(/^`|`$/gu, '').trim();
64
+ if (isSafeControlRelativePath(path) && path.startsWith('.agdf/control/') && !hasSymlinkComponent(root, path)) {
65
+ const file = containedRegularFile(root, path);
66
+ if (file.status === 'valid' && statSync(file.path).size <= UR_READ_LIMIT) {
67
+ const text = readFileSync(file.path, 'utf8');
68
+ urHeading = (text.match(/^#\s+(.+)$/mu)?.[1] ?? '').replace(/^UR:\s*/iu, '').trim();
69
+ const sourceLanguage = resolveArtifactPresentationLanguages(root, language).artifact_language;
70
+ localizedGoal = localizedDecisionFields('UR', text, { locale: String(language).split('-')[0], sourceLanguage, path }).fields.goal ?? null;
71
+ }
72
+ }
73
+ } catch (error) { if (error?.code === 'source_changed') throw error; }
74
+ const identity = runIdentity({ runId, runContent: content, urHeading });
75
+ return { run_title: identity.title_source === 'run_id' ? null : bounded(identity.title),
76
+ run_title_source: identity.title_source, goal: bounded(localizedGoal ?? identity.objective) };
77
+ }
78
+
79
+ // One run entry: inventory facts plus, when evaluated, the status card fields of its report.
80
+ // `naming` is readRunNaming's result for an evaluated run; without it the inventory names the run.
81
+ export function projectRunEntry(inventoryEntry, report, { registry = interactionLocales, language = 'en', naming = null } = {}) {
82
+ const authored = inventoryEntry.title_source === 'objective' ? inventoryEntry.title ?? null : null;
83
+ const base = {
84
+ run_id: inventoryEntry.run_id,
85
+ title: inventoryEntry.title ?? null,
86
+ // The stable human title, the same at every gate; null while only the Run ID could name the run.
87
+ run_title: naming ? naming.run_title : authored,
88
+ run_title_source: naming?.run_title_source ?? (authored ? 'objective' : 'run_id'),
89
+ // The goal in the display language where the UR states one, otherwise the authored objective.
90
+ goal: naming ? naming.goal : inventoryEntry.objective ?? null,
91
+ // The authored objective only, from the shared Run title rule; a template objective or a
92
+ // bare Run ID is no goal (CR finding C2).
93
+ objective: inventoryEntry.objective ?? null,
94
+ lifecycle: inventoryEntry.lifecycle ?? null,
95
+ valid: inventoryEntry.valid !== false,
96
+ revision: inventoryEntry.revision ?? null,
97
+ revision_id: inventoryEntry.revision_id ?? null,
98
+ last_activity: inventoryEntry.last_activity?.at ?? null,
99
+ findings: (inventoryEntry.findings ?? []).map(finding => finding.code),
100
+ };
101
+ if (!base.valid) base.unreadable_reason = diagnosisReason(inventoryEntry.findings ?? []);
102
+ // A run whose evaluation threw is reported with the bounded reason, never as an idle run (CR A7).
103
+ if (report?.evaluation_error) return withFigure({ ...base, evaluated: false, evaluation_error: report.evaluation_error });
104
+ if (!report?.status_card) return withFigure({ ...base, evaluated: false });
105
+ const card = report.status_card;
106
+ return withFigure({
107
+ ...base,
108
+ title: card.humanPresentation?.runTitle ?? base.title,
109
+ evaluated: true,
110
+ completion_confirmed: base.lifecycle === 'completed' && report.completion?.fulfilled === true,
111
+ status: card.status,
112
+ current_gate: card.current_gate,
113
+ path: card.breadcrumb.map(({ gate, status }) => ({ gate, status })),
114
+ missing_approval: card.missing_approval,
115
+ blocking_reason: card.blocking_condition,
116
+ blocking_text: localizeBlockingCondition(card.blocking_condition, { registry, requestedLocale: language }) ?? card.blocking_condition,
117
+ next_step: card.next_step,
118
+ next_step_text: localizeOperationalValue(card.next_step, { registry, requestedLocale: language }) ?? card.next_step,
119
+ user_action_required: card.user_action_required,
120
+ doctor_status: report.doctor_status,
121
+ mode: card.mode_slice_decision ?? card.mode ?? null,
122
+ });
123
+ }
124
+ const withFigure = entry => ({ ...entry, figure: deriveFigureState(entry) });
125
+
126
+ // Pure assembly of the versioned view from already evaluated parts.
127
+ export function projectRunView({ root, language, store, entries }) {
128
+ return {
129
+ schema_version: RUN_VIEW_SCHEMA,
130
+ root,
131
+ language,
132
+ store,
133
+ diagnosis: projectDiagnosis(entries.filter(entry => entry.listed !== false)),
134
+ runs: entries,
135
+ authorizes: false,
136
+ };
137
+ }
138
+
139
+ // Drift warnings (SD SDD-008, PRD AC-008): documents the run state binds with a recorded digest
140
+ // (effective artefact binding destination, latest evidence report per path) whose file now has another
141
+ // canonical digest from the node digest owner. Declared input files of a recording are not kept in
142
+ // the run state, so only bound documents are compared (contradiction C5 of this run). An unreadable
143
+ // run state yields no warning; the status card reports it.
144
+ export function readRunDrift(root, runId) {
145
+ let content;
146
+ try { content = readFileSync(join(root, runRelativePath(runId, '', 'RUN_STATE.md')), 'utf8'); } catch { return []; }
147
+ const declared = new Map();
148
+ const artefacts = readArtefactBindings(content);
149
+ // A binding a recorded source revision invalidated is superseded for Core, so its document being
150
+ // re-drafted is no drift (CR finding A5).
151
+ for (const receipt of artefacts.valid ? artefacts.active ?? [] : []) {
152
+ declared.set(receipt.destination.path, { document: receipt.destination.type, digest: receipt.destination.digest });
153
+ }
154
+ const evidence = readEvidenceBindings(content);
155
+ for (const row of evidence.valid ? evidence.bindings : []) {
156
+ declared.set(row.report.path, { document: row.report.path.split('/').at(-1).replace(/\.md$/u, ''), digest: row.report.digest });
157
+ }
158
+ const drift = [];
159
+ for (const [path, { document, digest }] of declared) {
160
+ const current = artefactFileDigest(root, path);
161
+ if (current === digest) continue;
162
+ drift.push({ document, path, recorded_digest: digest, current_digest: /^sha256:/u.test(current) ? current : null });
163
+ }
164
+ return drift;
165
+ }
166
+
167
+ // Active runs are evaluated; terminal and unreadable runs are summarized unless requested by id, so
168
+ // neither a large history nor many unreadable runs cost one evaluation per run. An unreadable run's
169
+ // reason and figure come from the inventory findings.
170
+ const needsEvaluation = (entry, requested) => requested.has(entry.run_id) || (entry.valid && entry.lifecycle === 'active');
171
+
172
+ // A write that lands during a capture invalidates it (source_changed); the read is repeated a bounded
173
+ // number of times before the change is reported (CR delta review RV-1).
174
+ export const CAPTURE_ATTEMPTS = 3;
175
+ export function captured(readRoot, project, capture = captureControlScope) {
176
+ for (let attempt = 1; ; attempt += 1) {
177
+ try { return capture(readRoot, view => project(view.root)).data; }
178
+ catch (error) { if (error?.code !== 'source_changed' || attempt >= CAPTURE_ATTEMPTS) throw error; }
179
+ }
180
+ }
181
+
182
+ // Reads inside bounded, revalidated control snapshots (TP T-002, SD section 4: captureControlScope,
183
+ // CR finding CIR-01): the inventory in one snapshot and each evaluated run with its drift in its own,
184
+ // so a read-boundary failure of one run (a linked file, a document outside the control folder, a read
185
+ // limit) marks only that run and the readable runs stay listed (SDD-003, RV-2). The root is resolved
186
+ // first, as MCP canonicalizes its target, so a junction or symlinked project root reads like its
187
+ // target; the view keeps the caller's spelling (RV-3). A missing root has no control folder (RV-5).
188
+ export function readRunView(root, { language = 'en', runIds = [] } = {}) {
189
+ const empty = store => projectRunView({ root, language, store, entries: [] });
190
+ if (!existsSync(root)) return empty({ status: 'no_control', reason: null });
191
+ let readRoot;
192
+ try { readRoot = realpathSync(root); } catch (error) { return empty({ status: 'unavailable', reason: boundedCode(error) }); }
193
+ const requested = new Set(runIds);
194
+ const evaluate = runId => {
195
+ try {
196
+ return captured(readRoot, base => {
197
+ const report = evaluateGateCheck(base, { runId, ignoreRunIdEnv: true, presentationLanguage: language });
198
+ return { report, drift: report?.status_card ? readRunDrift(base, runId) : null, naming: readRunNaming(base, runId, language) };
199
+ });
200
+ } catch (error) { return { report: { evaluation_error: boundedCode(error) }, drift: null, naming: null }; }
201
+ };
202
+ const entryOf = (inventoryEntry, evaluated) => {
203
+ const entry = projectRunEntry(inventoryEntry, evaluated?.report ?? null, { language, naming: evaluated?.naming ?? null });
204
+ return entry.evaluated && entry.valid !== false && evaluated.drift ? { ...entry, drift: evaluated.drift } : entry;
205
+ };
206
+ let inventory = null, store;
207
+ try {
208
+ inventory = captured(readRoot, base => readRunInventory(base, { language, observe: false }));
209
+ store = { status: inventory.state === 'absent' ? 'no_control' : 'ok', reason: null };
210
+ } catch (error) {
211
+ store = { status: 'unavailable', reason: boundedCode(error) };
212
+ // An unsupported layout lists no run, but its run folders can be counted, so a consumer names count
213
+ // and reason instead of "no open runs" (PRD AC-002, TP T-004). A failing count leaves the field out.
214
+ if (store.reason === 'control_layout_unsupported') {
215
+ try { store.run_folders = captured(readRoot, base => runFolderEntries(base).length); } catch { /* count unknown */ }
216
+ }
217
+ }
218
+ const listed = inventory?.runs ?? [];
219
+ const entries = listed.map(entry => entryOf(entry, needsEvaluation(entry, requested) ? evaluate(entry.run_id) : null));
220
+ for (const runId of requested) {
221
+ if (listed.some(entry => entry.run_id === runId)) continue;
222
+ // Requested but not listed by the inventory (for example behind an unsupported layout):
223
+ // evaluated for its card, never counted in the diagnosis of listed runs.
224
+ entries.push({ ...entryOf({ run_id: runId, findings: [] }, evaluate(runId)), valid: null, listed: false });
225
+ }
226
+ return projectRunView({ root, language, store, entries });
227
+ }
@@ -4,6 +4,8 @@ const CRITERION_ID = /^[A-Z][A-Z0-9]*(?:-[A-Z0-9]+)*$/u;
4
4
  export const ACCEPTANCE_CRITERIA_FORMAT = Object.freeze({
5
5
  section: "Acceptance Criteria", declaration: "criterion_id: <stable id>",
6
6
  fields: "semicolon-separated inline fields or following bullet key: value lines",
7
+ description_fields: Object.freeze(["observable_success", "visible_feedback", "expected_effective_state"]),
8
+ description_rule: "For same-language approval rendering, provide at least one nonempty description field separately. Never concatenate field names or infer their meaning from combined keys.",
7
9
  id_pattern: CRITERION_ID.source,
8
10
  examples: Object.freeze([
9
11
  "## Acceptance Criteria\n- criterion_id: AC-001; observable_success: Saved choice remains selected",
@@ -24,6 +24,24 @@ export function closeoutContext(text) {
24
24
  }
25
25
  export const closeoutContextDigest = text => digest(`agdf-closeout-context/1\0${canonicalJson(closeoutContext(text))}`);
26
26
 
27
+ // Bindings a structured OR states; the same tables drive the check and the
28
+ // expectations returned with a refusal.
29
+ const OR_SOURCE_FIELDS = Object.freeze({ related_ur: 'UR', related_prd: 'PRD', related_sd: 'SD', related_tp: 'TP', related_qa_report: 'QA' });
30
+ const OR_GATE_ROWS = Object.freeze(['UR', 'PRD', 'SD', 'TP', 'Brownfield Review', 'Brownfield Analysis', 'CD+Tests', 'CR', 'QA', 'UAT']);
31
+ const OR_MEMORY_TARGETS = Object.freeze(['context_graph', 'sot_registry', 'scope_artifact', 'open_questions', 'none']);
32
+ const gateRowExpectation = (state, type) => ({
33
+ status: state.approvals.has(type) ? state.approvals.get(type).status : state.artefacts.get(type)?.status,
34
+ reference: state.artefacts.get(type)?.path || state.approvals.get(type)?.evidence,
35
+ });
36
+ function structuredOrExpectations(state, route) {
37
+ return {
38
+ fields: { ...Object.fromEntries(Object.entries(OR_SOURCE_FIELDS).map(([field, type]) => [field, state.artefacts.get(type)?.path ?? null])),
39
+ mode_slice_decision: route, current_gate: 'OR', decision: 'pass', required_approval: 'none' },
40
+ gate_state_rows: Object.fromEntries(OR_GATE_ROWS.map(type => [type, gateRowExpectation(state, type)])),
41
+ memory_target: OR_MEMORY_TARGETS, memory_fields: 'memory_reason and memory_refs need concrete text',
42
+ };
43
+ }
44
+
27
45
  // Shared observation of registered OR and prepared OR candidates. Legacy reports retain
28
46
  // their documented formats; the new writer additionally requires the complete template.
29
47
  export function evaluateCloseoutReadiness(state, report, readArtefact, { prepared = false } = {}) {
@@ -85,14 +103,13 @@ export function evaluateCloseoutReadiness(state, report, readArtefact, { prepare
85
103
  ...Object.keys(context), 'next_allowed_action', 'required_approval', 'forbidden_until_then']) {
86
104
  if ([...report.matchAll(new RegExp(`^- ${field}:[ \\t]*(.*)$`, 'gmu'))].length !== 1) fail('or_field_ambiguous:' + field);
87
105
  }
88
- for (const [field, type] of Object.entries({ related_ur: 'UR', related_prd: 'PRD', related_sd: 'SD', related_tp: 'TP', related_qa_report: 'QA' })) {
106
+ for (const [field, type] of Object.entries(OR_SOURCE_FIELDS)) {
89
107
  if (value(report, field) !== state.artefacts.get(type)?.path) fail('or_source_reference_invalid:' + field);
90
108
  }
91
109
  if (value(report, 'mode_slice_decision') !== route || value(report, 'current_gate') !== 'OR' || value(report, 'decision') !== 'pass') fail('or_control_binding_invalid');
92
110
  const gateRows = tableRows(markdownSection(report, 'Gate State')).filter(row => row[0] !== 'Gate or step');
93
- for (const type of ['UR', 'PRD', 'SD', 'TP', 'Brownfield Review', 'Brownfield Analysis', 'CD+Tests', 'CR', 'QA', 'UAT']) {
94
- const rows = gateRows.filter(row => row[0] === type), expected = state.approvals.has(type) ? state.approvals.get(type).status : state.artefacts.get(type)?.status;
95
- const reference = state.artefacts.get(type)?.path || state.approvals.get(type)?.evidence;
111
+ for (const type of OR_GATE_ROWS) {
112
+ const rows = gateRows.filter(row => row[0] === type), { status: expected, reference } = gateRowExpectation(state, type);
96
113
  if (rows.length !== 1 || rows[0][1] !== expected || !concrete(rows[0][2])
97
114
  || cleanStatusCell(rows[0][2]) !== cleanStatusCell(reference)) fail('or_gate_state_unconfirmed:' + type);
98
115
  }
@@ -101,11 +118,12 @@ export function evaluateCloseoutReadiness(state, report, readArtefact, { prepare
101
118
  if (!concrete(text) || /<[^>]+>|\|[ \t]*\|/u.test(text)) fail('or_section_incomplete:' + section);
102
119
  }
103
120
  for (const section of ['Missing Evidence', 'Risks And Open Items']) if (/\|\s*(?:revise|block)\s*\|/u.test(markdownSection(report, section))) fail('or_required_obligation_open:' + section);
104
- if (!['context_graph', 'sot_registry', 'scope_artifact', 'open_questions', 'none'].includes(context.memory_target)
121
+ if (!OR_MEMORY_TARGETS.includes(context.memory_target)
105
122
  || !concrete(context.memory_reason) || !concrete(context.memory_refs)) fail('or_knowledge_decision_incomplete');
106
123
  if (value(report, 'required_approval') !== 'none') fail('or_required_approval_open');
107
124
  }
108
125
  }
109
126
  return { ready: findings.length === 0, findings, route, context_digest: closeoutContextDigest(report),
110
- parent_reconciliation: parent ?? null, programme_aggregation: programme ?? null };
127
+ parent_reconciliation: parent ?? null, programme_aggregation: programme ?? null,
128
+ ...(prepared && structured && findings.length ? { expected: structuredOrExpectations(state, route) } : {}) };
111
129
  }
@@ -2,8 +2,11 @@
2
2
  // run inventory and other `node:`-free readers share the same rule.
3
3
  const prompts = new Set(['describe the trustworthy outcome.', 'what outcome should become possible?',
4
4
  'which tp tasks are fully done, partially done or not done?', 'what remains unverified?', 'which risks remain and what is their impact?']);
5
+ // A bare generated Run ID (`run-<operation uuid>`) names the Run but states no outcome.
6
+ const generatedRunId = /^run-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/u;
5
7
  export function isDecisionContentPlaceholder(value) {
6
8
  if (typeof value !== 'string') return true;
7
9
  const text = value.trim().replace(/^`([^`]+)`$/u, '$1').replace(/\s+/gu, ' ').toLowerCase();
8
- return !text || prompts.has(text) || /^(?:todo|tbd|<[^>]+>|(?:draft|done|ready|blocked|pass|revise|block)(?:\s*\|\s*(?:draft|done|ready|blocked|pass|revise|block))+)$/.test(text);
10
+ return !text || prompts.has(text) || generatedRunId.test(text)
11
+ || /^(?:todo|tbd|<[^>]+>|(?:draft|done|ready|blocked|pass|revise|block)(?:\s*\|\s*(?:draft|done|ready|blocked|pass|revise|block))+)$/.test(text);
9
12
  }
@@ -9,7 +9,8 @@ import { isGateSatisfied, transitionDecisionForRunState } from "./gate-policy.js
9
9
  import { effectiveNextAllowedAction } from "./next-action.js";
10
10
  import { evaluateVerifiedChange, extractField, verifiedChangeEscalationTargets } from "./verified-change.js";
11
11
  import { gateApprovalStatus, isInternalStepSatisfied, modeSliceDecision, readArtefactHeading, readRunState, resolvedArtefactFile } from "./run-state.js";
12
- import { renderReviewableApproval } from "../control-state/run-presentation-render.js";
12
+ import { evaluateApprovalSummaryReadiness, renderApprovalSummaryIssue, renderReviewableApproval } from "../control-state/run-presentation-render.js";
13
+ import { readFileSync } from "../control-read/fs.js";
13
14
  import { evaluateUrReadiness } from "./ur-readiness.js";
14
15
  import { inspectDefinitionSources } from "./definition-sources.js";
15
16
  import { evaluatePrdReadiness } from "./prd-readiness.js";
@@ -158,7 +159,7 @@ export function isReadyUserGateApproval({ status, currentGate, missingApproval }
158
159
 
159
160
  function buildBreadcrumbPath(modeSliceDecision, currentGate, runState) {
160
161
  const gates = BREADCRUMB_PATH_TEMPLATES[modeSliceDecision] ?? ["UR"];
161
- return gates.map((gate) => {
162
+ return gates.map((gate, index) => {
162
163
  if (BREADCRUMB_STANDARD_GATES.includes(gate)) {
163
164
  if (gateApprovalStatus(runState, gate) === "approved") return { gate, status: "fulfilled" };
164
165
  if (gate === currentGate) return { gate, status: "current" };
@@ -169,6 +170,10 @@ function buildBreadcrumbPath(modeSliceDecision, currentGate, runState) {
169
170
  if (gate === currentGate) return { gate, status: "current" };
170
171
  if ((gate === "Verified Change" || gate === "Compact Delivery") && currentGate === "OR")
171
172
  return { gate, status: "fulfilled" };
173
+ // A path has one current entry: while an earlier gate is still the current one (a stored route
174
+ // with an unapproved UR), the route entry after it is open, not current by its route.
175
+ if (gates.slice(0, index).some((earlier) => earlier === currentGate && gateApprovalStatus(runState, earlier) !== "approved"))
176
+ return { gate, status: "open" };
172
177
  if (gate === "Verified Change" && modeSliceDecision === "verified_change")
173
178
  return { gate, status: "current" };
174
179
  if (gate === "Compact Delivery" && modeSliceDecision === "quick_task")
@@ -427,31 +432,58 @@ export function evaluateGateCheck(targetDir, selection = {}, dependencies = {})
427
432
  if (status === "open" && prdReadiness && transitionDecision.next_operation?.type !== "reassess_source_analysis" && isGateSatisfied(runState, "UR") && isInternalStepSatisfied(runState, "Brownfield Review")
428
433
  && ["structured_delivery", "structured_slice"].includes(modeSliceDecision(runState))) {
429
434
  const inputFacts = inspectDefinitionSources(targetDir, runState, extractField(runState.content, "run_id"), "PRD", ["UR", "Brownfield Review"]);
430
- if (inputFacts.issue) prdReadiness = { ready: false, open_decisions: [...prdReadiness.open_decisions,
435
+ if (inputFacts.issue) prdReadiness = { ...prdReadiness, ready: false, source_issue: inputFacts.issue, open_decisions: [...prdReadiness.open_decisions,
431
436
  renderDefinitionSourceRecovery(inputFacts.issue, { registry: interactionLocales, requestedLocale: presentationLocale })] };
432
437
  }
433
438
  if (status === "open" && currentGate === "PRD" && prdReadiness && !prdReadiness.ready) {
434
439
  status = "blocked";
440
+ const checks = prdReadiness.readiness_checks;
435
441
  blockingReason = "AGDF_PRD_DECISIONS_OPEN";
442
+ if (checks?.decisions_ready) {
443
+ const sourceCriteriaIncomplete = !checks.approval_summary.ready && [
444
+ "approval_summary_criterion_content_missing", "approval_summary_source_criteria_invalid",
445
+ "approval_summary_source_criteria_duplicate", "approval_summary_criteria_missing",
446
+ ].includes(checks.approval_summary.reason);
447
+ blockingReason = prdReadiness.source_issue || !checks.preview_ready || !checks.criteria_ready || sourceCriteriaIncomplete
448
+ ? "AGDF_PRD_READINESS_INCOMPLETE" : "AGDF_APPROVAL_SUMMARY_INCOMPLETE";
449
+ }
436
450
  allowed = ["complete the listed PRD readiness items together and record a new run revision"];
437
451
  forbidden = [...forbidden, "present or approve PRD before required decisions and acceptance criteria are ready"];
438
452
  // Fixed text keeps the card localizable; detailed gaps travel separately in prd_readiness.open_decisions.
439
453
  nextAllowedAction = "complete the open PRD readiness items together, then record the revision through the inspected current recording operation";
440
454
  }
441
- const sdReadiness = currentGate === "SD" && approvalArtefactReady ? evaluateSdReadiness(targetDir, runState) : null;
442
- const traceabilityReadiness = status === "open" && approvalArtefactReady && currentGate === "SD"
455
+ let sdReadiness = currentGate === "SD" && approvalArtefactReady ? evaluateSdReadiness(targetDir, runState) : null;
456
+ let traceabilityReadiness = status === "open" && approvalArtefactReady && currentGate === "SD"
443
457
  ? evaluateSdTraceability(targetDir, runState)
444
458
  : status === "open" && approvalArtefactReady && currentGate === "TP"
445
459
  ? evaluateTpTraceability(targetDir, runState)
446
460
  : null;
447
- if (status === "open" && sdReadiness && !sdReadiness.ready) {
461
+ // Presentation readiness belongs to the existing authoring gate, not to the
462
+ // traceability grammar. Use the same summary owner as preflight and rendering
463
+ // before a registered SD/TP draft can bypass its author and request approval.
464
+ let approvalSummaryReadiness = null;
465
+ if (status === "open" && approvalArtefactReady && ["SD", "TP"].includes(currentGate)) {
466
+ const path = runState.artefacts.get(currentGate).path;
467
+ const file = resolvedArtefactFile(targetDir, path);
468
+ const languages = resolveArtifactPresentationLanguages(targetDir, presentationLocale);
469
+ const summary = evaluateApprovalSummaryReadiness(currentGate, readFileSync(file, "utf8"), languages, { path });
470
+ if (!summary.ready) {
471
+ approvalSummaryReadiness = summary;
472
+ const issue = renderApprovalSummaryIssue(summary, { path, presentationLanguage: presentationLocale });
473
+ if (currentGate === "SD") sdReadiness = { ...sdReadiness, ready: false, decisions_ready: sdReadiness.ready,
474
+ open_decisions: [...sdReadiness.open_decisions, issue] };
475
+ else traceabilityReadiness = { ...traceabilityReadiness, ready: false, traceability_ready: traceabilityReadiness.ready,
476
+ open_items: [...traceabilityReadiness.open_items, issue] };
477
+ }
478
+ }
479
+ if (status === "open" && sdReadiness && !sdReadiness.ready && sdReadiness.decisions_ready !== true) {
448
480
  status = "blocked";
449
481
  blockingReason = "AGDF_SD_DECISIONS_OPEN";
450
482
  allowed = ["complete the listed SD readiness items together and record a new run revision"];
451
483
  forbidden = [...forbidden, "present or approve SD before required design decisions are ready"];
452
484
  nextAllowedAction = "complete the open SD readiness items together, then record the revision with the shared artefact writer";
453
485
  }
454
- if (status === "open" && traceabilityReadiness && !traceabilityReadiness.ready) {
486
+ if (status === "open" && traceabilityReadiness && !traceabilityReadiness.ready && traceabilityReadiness.traceability_ready !== true) {
455
487
  status = "blocked";
456
488
  blockingReason = currentGate === "SD" ? "AGDF_SD_TRACEABILITY_INCOMPLETE" : "AGDF_TP_TRACEABILITY_INCOMPLETE";
457
489
  allowed = [currentGate === "SD"
@@ -462,6 +494,15 @@ export function evaluateGateCheck(targetDir, selection = {}, dependencies = {})
462
494
  ? "complete the listed SD traceability rows, then record the revision through the inspected current recording operation"
463
495
  : "complete the listed TP traceability rows, then record the revision through the inspected current recording operation";
464
496
  }
497
+ if (status === "open" && approvalSummaryReadiness) {
498
+ status = "blocked";
499
+ blockingReason = "AGDF_APPROVAL_SUMMARY_INCOMPLETE";
500
+ }
501
+ if (blockingReason === "AGDF_APPROVAL_SUMMARY_INCOMPLETE") {
502
+ allowed = ["complete the current artefact approval summary and record a new run revision"];
503
+ forbidden = [...forbidden, "present or approve the current artefact before its required approval summary is ready"];
504
+ nextAllowedAction = "complete the current artefact approval summary, then record the revision through the inspected current recording operation";
505
+ }
465
506
  if (status === "open" && /^Approval: /u.test(missingApproval) && !approvalArtefactReady) {
466
507
  allowed = allowed.filter((action) => !/^request exact .* approval$/iu.test(action));
467
508
  if (/request exact approval: Approval: /iu.test(nextAllowedAction)) {
@@ -662,6 +703,7 @@ export function evaluateGateCheck(targetDir, selection = {}, dependencies = {})
662
703
  ...(prdReadiness ? { prd_readiness: prdReadiness } : {}),
663
704
  ...(sdReadiness ? { sd_readiness: sdReadiness } : {}),
664
705
  ...(traceabilityReadiness ? { traceability_readiness: traceabilityReadiness } : {}),
706
+ ...(approvalSummaryReadiness ? { approval_summary_readiness: approvalSummaryReadiness } : {}),
665
707
  next_gate_after_approval: postApproval.next_gate_after_approval,
666
708
  allowed_after_approval: postApproval.allowed_after_approval,
667
709
  allowed,
@@ -6,6 +6,8 @@ export function extractField(content, field) {
6
6
 
7
7
  export const verifiedChangeEscalationTargets = new Set(["structured_slice", "structured_delivery"]);
8
8
  export const STRUCTURED_REQUIRED_REVIEWS = Object.freeze(['TP Review', 'Clean Implementation Review']);
9
+ // The skill that owns each required review report.
10
+ export const REVIEW_SKILLS = Object.freeze({ 'TP Review': 'task-plan-review', 'Clean Implementation Review': 'clean-implementation-review' });
9
11
  // `Clean Review` is the supported legacy name of the Clean Implementation Review row.
10
12
  export const reviewArtefactType = (state, step) => step === 'Clean Implementation Review' && !state.artefacts.get(step)?.path
11
13
  && state.artefacts.get('Clean Review')?.path ? 'Clean Review' : step;
@@ -1,6 +1,6 @@
1
1
  import { extractField, verifiedChangeEscalationTargets } from "./gate-policy-inputs.js";
2
2
  import { gateApprovalStatus, gateArtefactStatus, isDurableGateArtefactSatisfied, isInternalStepSatisfied, modeSliceDecision } from "./run-state-policy.js";
3
- import { STRUCTURED_REQUIRED_REVIEWS, reviewArtefactType } from "./gate-policy-inputs.js";
3
+ import { REVIEW_SKILLS, STRUCTURED_REQUIRED_REVIEWS, reviewArtefactType } from "./gate-policy-inputs.js";
4
4
 
5
5
 
6
6
  // Shared policy over prepared facts. The Core supplies its validated receipt reader;
@@ -310,8 +310,9 @@ function gateDecisionForRunState(runState, verifiedChange = null) {
310
310
  const acceptedPlanDeviation = runState.qa_acceptance?.eligible || runState.qa_acceptance?.accepted;
311
311
  const structuredBeforeQaApproval = ["structured_slice", "structured_delivery"].includes(modeSliceDecision(runState))
312
312
  && gateApprovalStatus(runState, "QA") !== "approved";
313
- if (structuredBeforeQaApproval && STRUCTURED_REQUIRED_REVIEWS.some(step => !isInternalStepSatisfied(runState, reviewArtefactType(runState, step))
314
- && !(step === "TP Review" && acceptedPlanDeviation && runState.artefacts.get(step)?.status === "revise"))) {
313
+ const pendingReview = structuredBeforeQaApproval && STRUCTURED_REQUIRED_REVIEWS.find(step => !isInternalStepSatisfied(runState, reviewArtefactType(runState, step))
314
+ && !(step === "TP Review" && acceptedPlanDeviation && runState.artefacts.get(step)?.status === "revise"));
315
+ if (pendingReview) {
315
316
  return {
316
317
  status: "open",
317
318
  current_gate: "QA",
@@ -320,6 +321,9 @@ function gateDecisionForRunState(runState, verifiedChange = null) {
320
321
  allowed: ["record TP Review and Clean Implementation Review", "run QA gate"],
321
322
  forbidden: ["request QA approval", "request UAT approval", "release", "claim delivery readiness"],
322
323
  next_allowed_action: "Record TP Review and Clean Implementation Review before requesting Approval: QA.",
324
+ // Names the review owed next so authoring offers that report's forms, not the QA report's.
325
+ next_operation: { type: "record_required_review", skill_id: REVIEW_SKILLS[pendingReview], operation_key: "review.record",
326
+ actor: "agent", effect: "preparation", gate: "QA", internal_step: pendingReview },
323
327
  };
324
328
  }
325
329
  // A QA report recorded before current evidence (for example reviews recorded after it)
@@ -22,7 +22,8 @@ export function evaluatePrdReadiness(targetDir, runState, { presentationLanguage
22
22
  return { ready: false, open_decisions: ["Approval Decisions table is empty or malformed"] };
23
23
  }
24
24
  const open = [];
25
- try { previewForState(targetDir, runState); } catch (error) { open.push(error.message); }
25
+ let previewReady = true, previewIssue;
26
+ try { previewForState(targetDir, runState); } catch (error) { previewReady = false; previewIssue = error.message; }
26
27
  const seen = new Set();
27
28
  const incomplete = (value) => !value || /^(?:<|tbd\b|to confirm\b)/iu.test(value);
28
29
  for (const [decision, timing, status, resolution, owner, ...extra] of rows.slice(2)) {
@@ -38,6 +39,8 @@ export function evaluatePrdReadiness(targetDir, runState, { presentationLanguage
38
39
  // [ \t] rather than \s: an empty Owner line must not capture the following line.
39
40
  const owner = content.match(/^Owner:[ \t]*(.*)$/mu)?.[1]?.trim();
40
41
  if (incomplete(owner) || /\bto confirm\b|named individual/iu.test(owner)) open.unshift("Named PRD owner");
42
+ const decisionsReady = open.length === 0;
43
+ if (!previewReady) open.unshift(previewIssue);
41
44
  const criteria = evaluatePrdCriteriaReadiness(content);
42
45
  open.push(...criteria.open_items);
43
46
  // Use the presentation owner's validator before a registered draft can take the ready route.
@@ -47,5 +50,7 @@ export function evaluatePrdReadiness(targetDir, runState, { presentationLanguage
47
50
  if (!summary.ready) open.push(renderApprovalSummaryIssue(summary, {
48
51
  path, presentationLanguage: languages.presentation_language,
49
52
  }));
50
- return { ready: open.length === 0, open_decisions: open };
53
+ return { ready: open.length === 0, open_decisions: open,
54
+ readiness_checks: { decisions_ready: decisionsReady, preview_ready: previewReady, criteria_ready: criteria.ready,
55
+ approval_summary: summary } };
51
56
  }
@@ -222,6 +222,15 @@ export function readAuthoredContent(text, profile, { locale, sourceLanguage } =
222
222
  return sections === 1 && (spec.paragraph ? lines.length : Object.keys(fields).length) ? spec.paragraph ? lines.join(' ') : fields : null;
223
223
  }
224
224
 
225
+ // Authoring guidance owned next to the parser that enforces it. Only a level-1
226
+ // title's metadata or a level-2 "Decision" section carries the result; a
227
+ // "## Code Review" style heading closes the readable metadata block.
228
+ export const REPORT_DECISION_FORMAT = Object.freeze({
229
+ section: '## Decision',
230
+ field: '- decision: <pass|revise|block>',
231
+ instruction: 'State the result in a level-2 "## Decision" section whose first line is "- decision: <value>". The value must equal the decision supplied when recording. A result under any other heading is not read.',
232
+ });
233
+
225
234
  // Observe an authored technical result, never decide or approve QA. The closed
226
235
  // internal opt-in preserves analysis not_applicable; QA's domain stays unchanged.
227
236
  export function readReportDecision(text, { allowNotApplicable = false } = {}) {
@@ -45,6 +45,49 @@ function designDecisionIds(value) {
45
45
  return text.split(",").map((item) => item.trim().toUpperCase());
46
46
  }
47
47
 
48
+ const JSON_TYPE_METAVARIABLE = /^<(?:uuid|string|non-empty string|number|integer|(?:positive|non-negative) (?:integer|number)|boolean|null|object|array)>$/iu;
49
+
50
+ // Only typed JSON string values in an explicitly labelled schema/example are
51
+ // metavariables. Literal JSON keys may name words such as "todo"; angle-bracket
52
+ // key prompts, unknown values, arbitrary code and author fields stay checked.
53
+ function schemaExampleText(code) {
54
+ let parsed;
55
+ try { parsed = JSON.parse(code); } catch { return code; }
56
+ if (parsed === null || typeof parsed !== 'object') return code;
57
+ return code.replace(/"(?:\\.|[^"\\])*"/gu, (quoted, offset) => {
58
+ const key = /^[ \t]*:/u.test(code.slice(offset + quoted.length));
59
+ const value = JSON.parse(quoted);
60
+ if (key && !/<[^>]+>/u.test(value)) return '"literal-key"';
61
+ return JSON.stringify(!key && JSON_TYPE_METAVARIABLE.test(value) ? value.slice(1, -1) : value);
62
+ });
63
+ }
64
+
65
+ // A quoted command such as `done <id>` is concrete CLI syntax. Schema examples
66
+ // are permitted only in the decision clause, never instead of its rationale or
67
+ // consequence. The source text itself is never changed.
68
+ function unfinishedDecisionPrompts(value, { schemaExamples = false } = {}) {
69
+ const text = value.replace(/`([^`\n]+)`/gu, (span, code, offset) => {
70
+ if (/^[a-z][a-z0-9._/-]*(?:[ \t]+(?:--?[a-z0-9][a-z0-9_-]*|[a-z0-9._/-]+|<[a-z][a-z0-9_-]*>))+$/iu.test(code))
71
+ return code.replace(/<([a-z][a-z0-9_-]*)>/giu, '$1');
72
+ if (schemaExamples && /\b(?:(?:json[ \t]+)?schema(?:[ \t]+example)?|json[ \t]+example)[ \t]*[:=]?[ \t]*$/iu.test(value.slice(0, offset)))
73
+ return schemaExampleText(code);
74
+ return span;
75
+ });
76
+ // Preserve the original unfinished-field prefix guard even when an author
77
+ // has not closed its opening angle bracket yet.
78
+ return [...new Set(text.match(/<[^>]+>|^<[^>\s;]*|\b(?:tbd|to confirm|todo)\b/giu) ?? [])];
79
+ }
80
+
81
+ function decisionClauses(detail) {
82
+ // Semicolons or field-looking strings inside literal examples cannot declare
83
+ // the required author fields. Keep character offsets into the original text.
84
+ const labels = [...detail.replace(/`[^`\n]+`/gu, span => '_'.repeat(span.length))
85
+ .matchAll(/(?:^|;[ \t]*)(rationale|consequence|trade-off):[ \t]*/giu)];
86
+ return [{ field: 'decision', text: detail.slice(0, labels[0]?.index ?? detail.length).trim() },
87
+ ...labels.map((label, index) => ({ field: label[1].toLowerCase() === 'rationale' ? 'rationale' : 'consequence',
88
+ text: detail.slice(label.index + label[0].length, labels[index + 1]?.index ?? detail.length).trim() }))];
89
+ }
90
+
48
91
  function architectureDecisionIds(markdown) {
49
92
  const body = section(markdown, "Architecture Decisions");
50
93
  const openItems = [];
@@ -54,7 +97,7 @@ function architectureDecisionIds(markdown) {
54
97
  for (const line of body.split("\n").map((item) => item.trim()).filter((item) => /^[-*]\s+/u.test(item))) {
55
98
  const decision = line.replace(/^[-*]\s+/u, "").trim();
56
99
  if (/^none\b/iu.test(decision)) {
57
- if (!reasonedNone(decision) || /<[^>]+>|\b(?:tbd|to confirm|todo)\b/iu.test(decision)) {
100
+ if (!reasonedNone(decision) || unfinishedDecisionPrompts(decision).length) {
58
101
  openItems.push("State why no binding SD decision is needed after 'none'");
59
102
  }
60
103
  if (none || ids.length) openItems.push("SD cannot combine 'none' with binding design decisions");
@@ -70,12 +113,18 @@ function architectureDecisionIds(markdown) {
70
113
  if (none) openItems.push("SD cannot combine 'none' with binding design decisions");
71
114
  if (ids.includes(id)) openItems.push(`Duplicate SD design decision ID: ${id}`);
72
115
  ids.push(id);
73
- const detail = match[2];
74
- const rationale = detail.match(/(?:^|;\s*)rationale:\s*([^;]+)/iu)?.[1]?.trim();
75
- const consequence = detail.match(/(?:^|;\s*)(?:consequence|trade-off):\s*([^;]+)/iu)?.[1]?.trim();
76
- if (unfinished(detail) || /<[^>]+>|\b(?:tbd|to confirm|todo)\b/iu.test(detail)
77
- || unfinished(rationale) || unfinished(consequence)) {
78
- openItems.push(`SD design decision ${id} needs a concrete rationale and consequence`);
116
+ const clauses = decisionClauses(match[2]);
117
+ for (const field of ['decision', 'rationale', 'consequence']) {
118
+ const declarations = clauses.filter(clause => clause.field === field);
119
+ if (declarations.length > 1)
120
+ openItems.push(`SD design decision ${id} needs exactly one nonempty ${field}: field; found ${declarations.length} declarations`);
121
+ else if (!declarations.length || !declarations[0].text)
122
+ openItems.push(field === 'decision' ? `SD design decision ${id} needs a concrete decision statement`
123
+ : `SD design decision ${id} is missing a nonempty ${field}: field`);
124
+ }
125
+ for (const clause of clauses) {
126
+ const prompts = unfinishedDecisionPrompts(clause.text, { schemaExamples: clause.field === 'decision' });
127
+ if (prompts.length) openItems.push(`SD design decision ${id} contains unresolved author prompts in ${clause.field}: ${prompts.slice(0, 8).map(token => JSON.stringify(token)).join(', ')}${prompts.length > 8 ? ` (${prompts.length - 8} more)` : ''}`);
79
128
  }
80
129
  }
81
130
  if (!ids.length && !none) openItems.push("List binding SD decisions by SDD ID, or record a reasoned none");
@@ -192,7 +241,7 @@ export function evaluateTpTraceability(targetDir, runState) {
192
241
  for (const column of ["expected_result", "evidence"]) if (unfinished(row[column])) openItems.push(`TP scenario ${scenario || "without id"} needs ${column}`);
193
242
  const expectedDecisions = decisionsByCriterion.get(criterion) ?? [];
194
243
  if (expectedDecisions.length) {
195
- if (!expectedDecisions.includes(decision)) openItems.push(`TP scenario ${scenario || "without id"} must reference an SD decision for ${criterion}`);
244
+ if (!expectedDecisions.includes(decision)) openItems.push(`TP scenario ${scenario || "without id"} for ${criterion} has design_decision_id ${decision || "empty"}; set that table column to one of the mapped SD IDs: ${expectedDecisions.join(", ")}. Scenario prose cannot replace this cell.`);
196
245
  else {
197
246
  if (!verifiedDecisions.has(criterion)) verifiedDecisions.set(criterion, new Set());
198
247
  verifiedDecisions.get(criterion).add(decision);