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
@@ -1,14 +1,30 @@
1
1
  import { readControlLayout } from './control-layout.js';
2
- import { prepareRunContentState } from '../control-evaluation/run-state.js';
2
+ import { prepareRunContentState, readArtefactHeading } from '../control-evaluation/run-state.js';
3
3
  import { transitionDecisionForRunState } from '../control-evaluation/gate-policy.js';
4
+ import { evaluateGateCheck } from '../control-evaluation/gate-check.js';
5
+ import { projectCockpitAssessment } from '../control-inspect/run-classification.js';
6
+ import { projectWorkSituation } from '../control-inspect/work-situation.js';
7
+ import { runClosure } from './run-operations.js';
4
8
  import { existsSync } from "../control-read/fs.js";
5
9
  import { join } from "node:path";
6
10
  import { discoverRuns } from "./run-state-reader.js";
7
11
  import { buildRunInventory } from "./run-inventory.js";
12
+ import { parseControlState } from './run-state-parser.js';
13
+ import { runSealState, listedArtefactPaths } from './run-seal.js';
14
+ import { isSafeControlRelativePath } from './contained-file.js';
15
+
16
+ const READ_BOUNDARY_CODES = ['source_changed', 'resource_limit', 'resource_denied', 'timeout'];
17
+ const inControlScope = path => isSafeControlRelativePath(path) && path.startsWith('.agdf/control/');
18
+ // The detail reader's boundary: a run registering sources outside .agdf/control cannot be proven here.
19
+ const registersOnlyControlSources = content => listedArtefactPaths(content).every(inControlScope);
8
20
 
9
21
  // Feeds the pure inventory from the run discovery of the current read view: each run's parsed text
10
- // and, when the full parser rejected it, its findings. No run state is read a second time.
11
- export function readRunInventory(root, { language = "en" } = {}) {
22
+ // and, when the full parser rejected it, its findings. No run state is read a second time. `observe: false`
23
+ // skips the per-run gate observation, which reads registered documents, for a caller that evaluates the
24
+ // runs itself (the companion run view, which reads each run in its own captured snapshot).
25
+ // `cockpitAssessment` evaluates active runs only, like the companion run view: terminal runs stay
26
+ // summarized history, so a long history costs no gate evaluation per run and per refresh.
27
+ export function readRunInventory(root, { language = "en", observe = true, includePresentation = false, cockpitAssessment = false } = {}) {
12
28
  if (!existsSync(join(root, '.agdf/control'))) return buildRunInventory(null, { language });
13
29
  readControlLayout(root);
14
30
  if (!existsSync(join(root, '.agdf/control/runs'))) return buildRunInventory([], { language,
@@ -18,12 +34,45 @@ export function readRunInventory(root, { language = "en" } = {}) {
18
34
  const store = discovered.filter((run) => run.run_id === "<repository>");
19
35
  const sources = discovered.filter(run => run.run_id !== '<repository>').map(run => {
20
36
  const source = { run_id: run.run_id, ...(typeof run.content === 'string' ? { text: run.content } : {}), findings: run.valid ? [] : run.findings };
21
- if (run.valid) {
37
+ if (includePresentation && typeof run.content === 'string') {
38
+ let name = '', seal = 'unconfirmed';
39
+ try {
40
+ const ur = parseControlState(run.content).artefacts.get('UR');
41
+ const path = String(ur?.path ?? '').replace(/^`|`$/g, '').trim();
42
+ if (inControlScope(path)) name = readArtefactHeading(root, ur).replace(/^UR:\s*/i, '').trim();
43
+ } catch { /* An unreadable title must not hide the inventory. */ }
44
+ try {
45
+ if (registersOnlyControlSources(run.content)) {
46
+ const result = runSealState(root, run.content).status;
47
+ seal = result === 'valid' ? 'valid' : result === 'unsealed' ? 'unsealed'
48
+ : ['invalid', 'content_changed', 'approvals_changed'].includes(result) ? 'invalid' : 'unconfirmed';
49
+ }
50
+ } catch { /* Unavailable evidence cannot prove a seal state. */ }
51
+ source.presentation = { name: name || null, seal };
52
+ }
53
+ if (run.valid && observe) {
22
54
  try {
23
55
  const state = prepareRunContentState(root, run.content, run.path), decision = transitionDecisionForRunState(state);
24
56
  source.observation = { current_gate: decision.current_gate, decision: decision.status, missing: decision.missing_approval,
25
57
  next_action: decision.next_allowed_action, presentation_decision: Boolean(decision.presentation_decision?.decided) };
26
- } catch { source.findings = [{ code: 'AGDF_RUN_OBSERVATION_UNAVAILABLE' }]; }
58
+ if (cockpitAssessment && run.meta?.lifecycle === 'active') {
59
+ let report = null;
60
+ if (registersOnlyControlSources(run.content)) { try { report = evaluateGateCheck(root, { runId: run.run_id, ignoreRunIdEnv: true }); } catch (error) {
61
+ if (READ_BOUNDARY_CODES.includes(error.code)) throw error;
62
+ // Preserve the Run but do not claim a verified assessment.
63
+ } }
64
+ const assessed = report ? projectCockpitAssessment(report, run.meta?.lifecycle) : { state: 'unconfirmed' };
65
+ source.observation.work_situation = projectWorkSituation({ assessment: assessed.state,
66
+ gate: report?.current_gate, blockingReason: report?.blocking_reason, missingApproval: report?.missing_approval,
67
+ persistedGate: report ? state.current_gate : undefined, persistedNext: state.next_allowed_action, nextAllowedAction: report?.next_allowed_action,
68
+ closureOutcome: runClosure(run.content)?.outcome });
69
+ if (report) Object.assign(source.observation, { current_gate: report.current_gate, decision: report.status,
70
+ missing: report.missing_approval, next_action: report.next_allowed_action });
71
+ }
72
+ } catch (error) {
73
+ if (cockpitAssessment && READ_BOUNDARY_CODES.includes(error.code)) throw error;
74
+ source.findings = [{ code: 'AGDF_RUN_OBSERVATION_UNAVAILABLE' }];
75
+ }
27
76
  }
28
77
  return source;
29
78
  });
@@ -3,7 +3,9 @@
3
3
  // Callers pass validity findings from the full parser; this module never validates receipts.
4
4
  import { scalarFields, sectionTableRows, projectRunFacts } from "./run-state-document.js";
5
5
  import { RUN_ID_PATTERN } from "./run-identity.js";
6
- import { isDecisionContentPlaceholder } from "../control-evaluation/decision-content-placeholder.js";
6
+ import { normalizedRunTitle, runIdentity } from "./run-title.js";
7
+
8
+ export { normalizedRunTitle };
7
9
 
8
10
  export const RUN_INVENTORY_SCHEMA_VERSION = "1";
9
11
  export const RUN_INVENTORY_LIFECYCLES = Object.freeze(["active", "completed", "superseded", "abandoned"]);
@@ -42,29 +44,10 @@ const ISO_TIME = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$/u;
42
44
  const plain = value => String(value ?? "").replace(/`/gu, "").trim();
43
45
  const clip = text => (text.length > TITLE_LIMIT ? `${text.slice(0, TITLE_LIMIT - 1)}…` : text);
44
46
 
45
- // The run-ID title every reader shows when no authored title exists.
46
- export function normalizedRunTitle(runId) {
47
- const words = String(runId ?? "").replace(/[._-]+/g, " ").replace(/\s+/g, " ").trim();
48
- return words ? words.replace(/\b\p{L}/gu, (letter) => letter.toUpperCase()) : "AGDF run";
49
- }
50
-
51
- // Lines of one level-two section up to the next heading; an empty section stays empty.
52
- function sectionLines(text, heading) {
53
- const lines = text.split("\n"), start = lines.findIndex(line => line.trimEnd() === `## ${heading}`);
54
- if (start < 0) return [];
55
- const rest = lines.slice(start + 1), end = rest.findIndex(line => /^#{1,2} /u.test(line));
56
- return end < 0 ? rest : rest.slice(0, end);
57
- }
58
-
59
- function objectiveTitle(text, runId) {
60
- // The first paragraph, so hard-wrapped objectives stay whole.
61
- const lines = sectionLines(text, "Objective").map(value => value.trim()), first = lines.findIndex(Boolean);
62
- const paragraph = first < 0 ? [] : lines.slice(first), end = paragraph.indexOf("");
63
- const line = (end < 0 ? paragraph : paragraph.slice(0, end)).join(" ");
64
- const stripped = line.replace(/^(?:[-*>]|#+|\d+\.)\s+/u, "").replace(/\*\*|__|`/gu, "").replace(/\s+/gu, " ").trim();
65
- return isDecisionContentPlaceholder(stripped)
66
- ? { title: normalizedRunTitle(runId), title_source: "run_id" }
67
- : { title: clip(stripped), title_source: "objective" };
47
+ // The inventory reads no UR document, so its title source is the Objective or the Run ID.
48
+ function titleFacts(text, runId) {
49
+ const { title, title_source, objective } = runIdentity({ runId, runContent: text });
50
+ return { title: clip(title), title_source, objective: objective === null ? null : clip(objective) };
68
51
  }
69
52
 
70
53
  // Base64url receipt cells decoded for display facts only; undecodable cells are skipped.
@@ -126,17 +109,19 @@ function entryOf(source, language) {
126
109
  const gateResult = facts?.artefacts.get(gate === 'Quick Task Execution' ? 'CR' : gate)?.status ?? null;
127
110
  const presentationDecision = source.observation?.presentation_decision === true;
128
111
  const missing = source.observation?.missing === 'none' ? '' : source.observation?.missing ?? '';
129
- const attention = runAttention({ lifecycle, valid, decision, gateResult, presentationDecision, missing });
112
+ const situation = source.observation?.work_situation;
113
+ const attention = situation?.code ?? runAttention({ lifecycle, valid, decision, gateResult, presentationDecision, missing });
130
114
  const revision = /^[1-9]\d*$/u.test(meta.get("revision") ?? "") ? Number(meta.get("revision")) : null;
131
115
  const index = languageIndex(language);
132
116
  return {
133
117
  run_id: runId,
134
- ...(text ? objectiveTitle(text, runId) : { title: normalizedRunTitle(runId), title_source: "run_id" }),
118
+ ...titleFacts(text, runId),
119
+ ...(source.presentation ? { presentation: source.presentation } : {}),
135
120
  valid,
136
121
  lifecycle: valid ? lifecycle : null,
137
122
  current_gate: gate,
138
123
  decision,
139
- attention: { code: attention, label: LABELS[attention][index] },
124
+ attention: { code: attention, label: situation ? (index === 1 ? situation.de : situation.en) : LABELS[attention][index] },
140
125
  basis: revision === null ? TEXT.basisUnknown[index]() : TEXT.basis[index](revision),
141
126
  last_activity: text ? lastActivity(decoded) : { at: null, source: "none", precision: null },
142
127
  revision,
@@ -15,8 +15,8 @@ import { containedRegularFile, hasSymlinkComponent } from './contained-file.js';
15
15
  import { readPendingSourceRevisionJournal } from './run-step-transaction.js';
16
16
  import { inspectPlannedOperation, inspectPlannedSelection } from './planned-entry.js';
17
17
 
18
- export const MATERIAL_LIMITS = Object.freeze({ part: 16384, file: 131072, set: 524288, sets: 4, total: 2097152,
19
- lifetime: 600000, idle: 120000 });
18
+ import { MATERIAL_LIMITS } from './material-limits.js';
19
+ export { MATERIAL_LIMITS } from './material-limits.js';
20
20
 
21
21
  // A rejected transfer step names its concrete cause; the reason code stays stable for clients.
22
22
  const MATERIAL_RECOVERY = Object.freeze({
@@ -108,23 +108,34 @@ export function createRunMaterialStore({ now = Date.now } = {}) {
108
108
  const state = current(input), p = input.command.payload;
109
109
  expire();
110
110
  let row;
111
- if (p.action === 'begin') {
111
+ if (p.action === 'begin' || p.action === 'put') {
112
+ // The small-text path bundles only private transfer work. Validate the
113
+ // whole set before allocating; canonical recording still uses its owner.
114
+ const files = p.action === 'put' ? p.files.map(({ slot, content }) => {
115
+ const bytes = Buffer.from(content, 'utf8');
116
+ if (bytes.length > MATERIAL_LIMITS.inline || new TextDecoder('utf-8', { fatal: true }).decode(bytes) !== content)
117
+ throw Error('material_text_invalid');
118
+ return { slot, bytes: bytes.length, content, data: bytes };
119
+ }) : p.files;
112
120
  const request = digest(canonicalJson(input));
113
121
  row = sets.get(input.operation_id);
114
122
  if (row) {
115
123
  if (row.request !== request || row.binding !== binding(input)) throw Error('operation_payload_conflict');
116
124
  } else {
117
- const size = p.files.reduce((n, f) => n + f.bytes, 0);
125
+ const size = files.reduce((n, f) => n + f.bytes, 0);
118
126
  const resolutionBytes = currentInputResolution() ? Buffer.byteLength(canonicalJson(currentInputResolution())) : 0;
119
- if (!p.files.length || p.files.length > 4 || p.files.some(f => !Number.isSafeInteger(f.bytes) || f.bytes < 0 || f.bytes > MATERIAL_LIMITS.file)
127
+ if (!files.length || files.length > 4 || files.some(f => !Number.isSafeInteger(f.bytes) || f.bytes < 0 || f.bytes > MATERIAL_LIMITS.file)
120
128
  || size + resolutionBytes > MATERIAL_LIMITS.set || sets.size >= MATERIAL_LIMITS.sets
121
129
  || [...sets.values()].reduce((n, r) => n + r.size + r.resolutionBytes, size + resolutionBytes) > MATERIAL_LIMITS.total) throw Error('material_resource_limit');
122
130
  row = { request, binding: binding(input), size, created: now(), touched: now(), resolutions: new Map(), resolutionBytes: 0,
123
- files: p.files.map(f => ({ ...f, parts: [], received: 0, material_id: randomUUID(), content: null, digest: null })) };
131
+ files: files.map(f => ({ slot: f.slot, bytes: f.bytes, parts: f.data ? [f.data] : [],
132
+ received: f.data ? f.bytes : 0, material_id: randomUUID(), content: f.content ?? null,
133
+ digest: f.data ? digest(canonicalRunText(f.content)) : null })) };
124
134
  sets.set(input.operation_id, row);
125
135
  }
126
136
  rememberResolution(row, input);
127
- return envelope('accepted', null, { transfer_id: input.operation_id, files: row.files.map(({ slot, bytes, received }) => ({ slot, bytes, received })), limits: MATERIAL_LIMITS }, state);
137
+ return envelope('accepted', null, { transfer_id: input.operation_id, files: row.files.map(({ slot, bytes, received, content, material_id, digest }) => ({ slot, bytes, received,
138
+ ...(content !== null ? { sealed: true, reference: { material_id, digest } } : {}) })), limits: MATERIAL_LIMITS }, state);
128
139
  }
129
140
  row = rowFor(input, p.transfer_id);
130
141
  rememberResolution(row, input);
@@ -195,6 +206,13 @@ export function createRunMaterialStore({ now = Date.now } = {}) {
195
206
  // parts in that same set cannot be used for another current write.
196
207
  for (const [id, row] of sets) if (row.files.some(file => ids.has(file.material_id))) sets.delete(id);
197
208
  },
209
+ // Review facts (companion core SDD-008): the sealed text of one transfer for the runtime's bounded
210
+ // preview, or null when it is unknown or not sealed. It reads only; it is never a material grant.
211
+ sealedFiles(transferId) {
212
+ const row = sets.get(transferId);
213
+ if (closed || !row || row.files.some(file => file.content === null)) return null;
214
+ return row.files.map(({ slot, content, digest: hash }) => Object.freeze({ slot, content, digest: hash }));
215
+ },
198
216
  close() { closed = true; sets.clear(); },
199
217
  inspectOwnership() { expire(); return { sets: sets.size, bytes: [...sets.values()].reduce((n, r) => n + r.size, 0) }; },
200
218
  });
@@ -1,4 +1,4 @@
1
- import { readAcceptanceCriteria } from "../control-evaluation/traceability-readiness.js";
1
+ import { readAcceptanceCriteria, ACCEPTANCE_CRITERIA_FORMAT, TRACEABILITY_CONTRACT } from "../control-evaluation/traceability-readiness.js";
2
2
  import { createHash } from "node:crypto";
3
3
  import { readFileSync } from "../control-read/fs.js";
4
4
  import { basename } from "node:path";
@@ -43,6 +43,14 @@ export function presentationVersionComparison(root, state, gate, currentDigest)
43
43
  const MAX_APPROVAL_ARTEFACT_BYTES = 131072;
44
44
  const MAX_LOCALIZED_SUMMARY_ITEM_CHARS = 1200;
45
45
  const MAX_LOCALIZED_SUMMARY_CHARS = 24000;
46
+ const PRD_LOCALIZED_SUMMARY_FIELDS = Object.freeze([
47
+ { pattern: /^(?:[-*]\s*)?(?:Nutzerziel|User intent|Ziel|Goal)\s*:/iu,
48
+ de: '- Ziel:', en: '- Goal:', reason: 'approval_summary_user_goal_missing' },
49
+ { pattern: /^(?:[-*]\s*)?(?:Umfang|Scope|Produktumfang|Product scope)\s*:/iu,
50
+ de: '- Umfang:', en: '- Scope:', reason: 'approval_summary_scope_missing' },
51
+ { pattern: /^(?:[-*]\s*)?(?:Entscheidungen|Decisions|Geklärte Entscheidungen|Resolved decisions|Offene Entscheidungen|Open decisions)\s*:/iu,
52
+ de: '- Entscheidungen:', en: '- Decisions:', reason: 'approval_summary_decisions_missing', conditional: true },
53
+ ]);
46
54
  const SUMMARY_SECTIONS = Object.freeze({
47
55
  UR: [
48
56
  ["Problem", /problem|need|anlass/iu], ["Ziel", /goal|objective|ziel/iu],
@@ -83,8 +91,13 @@ const SUMMARY_LABELS_EN = Object.freeze({
83
91
  export const hash = (value) => `sha256:${createHash("sha256").update(value).digest("hex")}`;
84
92
 
85
93
  function compactSummaryText(value) {
86
- return value.replace(/\[([^\]]+)\]\([^)]*\)/gu, "$1").replace(/`([^`]+)`/gu, "$1")
87
- .replace(/<[^>]+>/gu, "").replace(/\s+/gu, " ").trim();
94
+ // Markup outside code spans is dropped. A code span naming syntax such as
95
+ // `node app.js <file>` keeps its backticks: unwrapped, Markdown would treat
96
+ // <file> as an HTML tag and the reader would lose it.
97
+ return value.replace(/\[([^\]]+)\]\([^)]*\)/gu, "$1")
98
+ .split(/(`[^`]+`)/u)
99
+ .map(part => /^`[^`]+`$/u.test(part) ? (part.includes("<") ? part : part.slice(1, -1)) : part.replace(/<[^>]+>/gu, ""))
100
+ .join("").replace(/\s+/gu, " ").trim();
88
101
  }
89
102
 
90
103
  function userFacingSummaryText(value) {
@@ -111,14 +124,14 @@ function substantiveMarkdown(markdown) {
111
124
  return markdown.replace(/^## AGDF Approval Summary \([^\r\n]*\)\s*\r?\n[\s\S]*?(?=^#{1,2}\s|(?![\s\S]))/gmu, "");
112
125
  }
113
126
 
114
- function criterionEntries(markdown) {
115
- const parsed = readAcceptanceCriteria(substantiveMarkdown(markdown));
127
+ function criterionEntries(markdown, source) {
128
+ const parsed = readAcceptanceCriteria(substantiveMarkdown(markdown), { source });
116
129
  if (parsed.diagnostics.length) throw Object.assign(new Error("approval_summary_source_criteria_invalid"), { diagnostics: parsed.diagnostics });
117
130
  return parsed.entries;
118
131
  }
119
132
 
120
133
  function criterionDescription(entry) {
121
- for (const field of ["observable_success", "visible_feedback", "expected_effective_state"]) {
134
+ for (const field of ACCEPTANCE_CRITERIA_FORMAT.description_fields) {
122
135
  const value = String(entry.fields[field] ?? "").trim();
123
136
  if (value) return capitalizeSummary(compactSummaryText(value));
124
137
  }
@@ -158,16 +171,35 @@ function validateLocalizedSummaryBlock(gate, block, sourceMarkdown, sourceLangua
158
171
  if (summaryIds.some((id) => !sourceSet.has(id))) throw new Error("approval_summary_criteria_unknown");
159
172
  if (summaryIds.length !== sourceIds.length || sourceIds.some((id) => !summaryIds.includes(id)))
160
173
  throw new Error("approval_summary_criteria_incomplete");
161
- if (!lines.some((line) => /^(?:[-*]\s*)?(?:Nutzerziel|User intent|Ziel|Goal)\s*:/iu.test(line)))
162
- throw new Error("approval_summary_user_goal_missing");
163
- if (!lines.some((line) => /^(?:[-*]\s*)?(?:Umfang|Scope|Produktumfang|Product scope)\s*:/iu.test(line)))
164
- throw new Error("approval_summary_scope_missing");
165
174
  const decisions = approvalDecisionEntries(sourceMarkdown);
166
- if (decisions.length && !lines.some((line) => /^(?:[-*]\s*)?(?:Entscheidungen|Decisions|Geklärte Entscheidungen|Resolved decisions|Offene Entscheidungen|Open decisions)\s*:/iu.test(line)))
167
- throw new Error("approval_summary_decisions_missing");
175
+ for (const field of PRD_LOCALIZED_SUMMARY_FIELDS)
176
+ if ((!field.conditional || decisions.length) && !lines.some(line => field.pattern.test(line))) throw new Error(field.reason);
168
177
  }
169
178
  }
170
179
 
180
+ // Syntax guidance comes from the presentation owner, never inferred product
181
+ // content. An incomplete source remains readable through its authoring route.
182
+ export function approvalSummaryAuthoringFormat(gate, markdown, languages) {
183
+ if (!languages.approval_summary_required || !['UR', 'PRD', 'SD', 'TP', 'QA'].includes(gate)) return null;
184
+ const locale = languages.presentation_language.toLowerCase().startsWith('de') ? 'de' : 'en';
185
+ const format = { heading: languages.approval_summary_heading, body_required: true,
186
+ required_fields: localizedDecisionFields(gate, '', { locale, sourceLanguage: languages.artifact_language }).gaps.map(gap => gap.expected),
187
+ instruction: 'Use the exact heading and a nonempty authored summary in the presentation language. Required fields are separate list declarations with concrete content; a heading or generic criteria paragraph does not replace them. This is syntax guidance, never supplied product content, review or approval.' };
188
+ if (gate === 'PRD') {
189
+ const decisions = approvalDecisionEntries(markdown);
190
+ format.required_fields = PRD_LOCALIZED_SUMMARY_FIELDS.filter(field => !field.conditional || decisions.length).map(field => field[locale]);
191
+ format.conditional_fields = [{ field: PRD_LOCALIZED_SUMMARY_FIELDS.find(field => field.conditional)[locale],
192
+ when: 'Required when the source PRD contains Approval Decisions rows.' }];
193
+ try {
194
+ const entries = criterionEntries(markdown);
195
+ format.criterion_fields = entries.map(entry => `- ${entry.id}:`);
196
+ format.criteria_state = entries.length ? 'available' : 'not_declared';
197
+ } catch { format.criterion_fields = []; format.criteria_state = 'source_invalid'; }
198
+ format.criteria_instruction = 'For every exact criterion_id in the authored PRD, write one separate list item beginning with that ID followed by a colon, exactly once. Retain the source IDs; do not combine them in a generic criteria item. If IDs are not yet available, complete the source criteria first.';
199
+ }
200
+ return format;
201
+ }
202
+
171
203
  function requiredLocalizedSummary(gate, markdown, languages, { path } = {}) {
172
204
  if (!languages.approval_summary_required) return null;
173
205
  const blocks = localizedSummaryBlocks(markdown).filter(block => block.locale === languages.presentation_language);
@@ -186,6 +218,11 @@ function requiredLocalizedSummary(gate, markdown, languages, { path } = {}) {
186
218
  export function evaluateApprovalSummaryReadiness(gate, markdown, languages, { path } = {}) {
187
219
  try {
188
220
  requiredLocalizedSummary(gate, markdown, languages, { path });
221
+ if (gate === "PRD" && markdown.includes(TRACEABILITY_CONTRACT)
222
+ && languages.artifact_language === languages.presentation_language.split("-")[0]) {
223
+ artifactSummary(gate, markdown, { language: languages.presentation_language,
224
+ sourceLanguage: languages.artifact_language, artefactPath: path });
225
+ }
189
226
  return Object.freeze({ ready: true, required_heading: languages.approval_summary_heading, reason: null });
190
227
  } catch (error) {
191
228
  if (!String(error.message).startsWith("approval_summary_")) throw error;
@@ -197,12 +234,25 @@ export function evaluateApprovalSummaryReadiness(gate, markdown, languages, { pa
197
234
  export function renderApprovalSummaryIssue(summary, { path, presentationLanguage }) {
198
235
  const locale = resolvePresentationLocale(interactionLocales, presentationLanguage);
199
236
  const pack = localePack(interactionLocales, locale), german = locale.split("-")[0] === "de";
200
- const expected = {
201
- approval_summary_user_goal_missing: german ? "- Ziel:" : "- Goal:",
202
- approval_summary_scope_missing: german ? "- Umfang:" : "- Scope:",
203
- approval_summary_decisions_missing: german ? "- Entscheidungen:" : "- Decisions:",
204
- approval_summary_field_unreadable: summary.diagnostics?.map(row => row.expected).join("` · `") || undefined,
205
- }[summary.reason] ?? summary.required_heading;
237
+ if (summary.reason === "approval_summary_criterion_content_missing") {
238
+ const fields = ACCEPTANCE_CRITERIA_FORMAT.description_fields.map(field => `\`${field}\``).join(" / ");
239
+ const locations = (summary.diagnostics ?? []).map(row =>
240
+ `- ${row.criterion_id}${row.line ? ` (${german ? 'Zeile' : 'line'} ${row.line})` : ''}`).join("\n");
241
+ return [
242
+ `${german ? 'PRD-Quellkriterien korrigieren' : 'Correct PRD source criteria'}: \`${path}\``,
243
+ `${pack.statusCard.summaryReason}: \`${summary.reason}\``,
244
+ locations,
245
+ german
246
+ ? `Je betroffenem Kriterium mindestens eines dieser Felder einzeln und mit Inhalt angeben: ${fields}. Zusammengesetzte Feldnamen werden nicht aufgeteilt.`
247
+ : `For each affected criterion, provide at least one separate nonempty field: ${fields}. Combined field names are not split.`,
248
+ german
249
+ ? 'Eine zusätzliche AGDF Approval Summary ersetzt diese Quellfelder nicht. Die Kriterien-IDs und den fachlichen Inhalt erhalten; über den bestehenden Autorpfad korrigieren und erneut prüfen.'
250
+ : 'An additional AGDF Approval Summary does not replace these source fields. Preserve criterion IDs and product intent; correct through the existing authoring route and recheck.',
251
+ ].filter(Boolean).join("\n");
252
+ }
253
+ const expected = PRD_LOCALIZED_SUMMARY_FIELDS.find(field => field.reason === summary.reason)?.[german ? 'de' : 'en']
254
+ ?? (summary.reason === 'approval_summary_field_unreadable' ? summary.diagnostics?.map(row => row.expected).join("` · `") || undefined : undefined)
255
+ ?? summary.required_heading;
206
256
  return [
207
257
  `${pack.statusCard.summaryRecovery}: \`${path}\``,
208
258
  `${pack.statusCard.summaryReason}: \`${summary.reason}\``,
@@ -210,7 +260,8 @@ export function renderApprovalSummaryIssue(summary, { path, presentationLanguage
210
260
  ].join("\n");
211
261
  }
212
262
 
213
- function sectionBody(markdown, pattern, contentPattern = null, maxItems = 3) {
263
+ // Pure summary extraction; exported so its text rules are tested directly.
264
+ export function sectionBody(markdown, pattern, contentPattern = null, maxItems = 3) {
214
265
  const lines = markdown.replace(/\r\n?/gu, "\n").split("\n");
215
266
  for (let index = 0; index < lines.length; index += 1) {
216
267
  const heading = lines[index].match(/^(#{2,6})\s+(?:\d+\.\s*)?(.+?)\s*#*\s*$/u);
@@ -233,6 +284,9 @@ function sectionBody(markdown, pattern, contentPattern = null, maxItems = 3) {
233
284
  }
234
285
  if (contentPattern && !contentPattern.test(line)) continue;
235
286
  const cleaned = userFacingSummaryText(line);
287
+ // A lead-in such as "covers exactly these points:" says nothing on its own;
288
+ // the items that follow it carry the content.
289
+ if (/:$/u.test(cleaned)) continue;
236
290
  if (!cleaned || /^(?:what|which|how|who|every field|specify|decision:|status:|gate:|date:|owner:)/iu.test(cleaned)
237
291
  || /^(?:ui_ux_impact|ux_intent_definition|primary_user_intent|success_signal|primary_decision_or_action):/iu.test(cleaned)) continue;
238
292
  body.push(cleaned);
@@ -275,14 +329,15 @@ function artifactSummary(gate, markdown, { runId, revisionId, language, sourceLa
275
329
  if (decision) items.unshift(`- ${german ? 'Entscheidung' : 'Decision'}: ${decision}`);
276
330
  }
277
331
  if (gate === "PRD") {
278
- const criteria = criterionEntries(source);
332
+ const criteria = criterionEntries(source, artefactPath);
279
333
  if (!criteria.length) throw new Error("approval_summary_criteria_missing");
280
334
  if (new Set(criteria.map((entry) => entry.id)).size !== criteria.length) throw new Error("approval_summary_source_criteria_duplicate");
281
- const criterionRows = criteria.map((entry) => {
282
- const description = criterionDescription(entry);
283
- if (!description) throw new Error("approval_summary_criterion_content_missing");
284
- return ` - ${entry.id}: ${description}`;
335
+ const missing = criteria.filter(entry => !criterionDescription(entry));
336
+ if (missing.length) throw Object.assign(new Error("approval_summary_criterion_content_missing"), {
337
+ diagnostics: missing.map(entry => ({ code: 'criterion_description_missing', source: entry.source,
338
+ line: entry.line, criterion_id: entry.id, expected: ACCEPTANCE_CRITERIA_FORMAT.description_fields })),
285
339
  });
340
+ const criterionRows = criteria.map(entry => ` - ${entry.id}: ${criterionDescription(entry)}`);
286
341
  items.push(`- ${german ? "Abnahmekriterien" : "Acceptance criteria"}:\n${criterionRows.join("\n")}`);
287
342
  const decisions = approvalDecisionEntries(source);
288
343
  if (decisions.length) {
@@ -300,6 +355,35 @@ function artifactSummary(gate, markdown, { runId, revisionId, language, sourceLa
300
355
  return { markdown: summary, digest: hash(summary) };
301
356
  }
302
357
 
358
+ // Cockpit presentation reuses the same language and summary owner as authoring checks.
359
+ // The structured rows are derived from that summary; no second content authority is created.
360
+ export function projectCockpitSummary(gate, markdown, languages, context = {}) {
361
+ if (!['UR', 'PRD', 'SD', 'TP'].includes(gate)) return null;
362
+ try {
363
+ const readiness = evaluateApprovalSummaryReadiness(gate, markdown, languages, { path: context.artefactPath });
364
+ if (!readiness.ready) return null;
365
+ const summary = artifactSummary(gate, markdown, { ...context, language: languages.presentation_language, sourceLanguage: languages.artifact_language });
366
+ const priorities = {
367
+ UR: [/^(?:Ziel|Goal)$/iu, /^(?:Umfang|Scope)$/iu, /^(?:Abnahme|Abnahmesignal|Acceptance)$/iu],
368
+ PRD: [/^(?:Ziel|Nutzerziel|Goal|User intent)$/iu, /^(?:Umfang|Produktumfang|Scope|Product scope)$/iu, /^(?:AC-[A-Z0-9-]+)$/iu],
369
+ SD: [/^(?:Lösung|Solution)$/iu, /^(?:Verantwortung|Ownership)$/iu, /^(?:Entscheidungen|Design decisions)$/iu],
370
+ TP: [/^(?:Aufgaben|Tasks)$/iu, /^(?:Tests)$/iu, /^(?:Risiken|Risks)$/iu],
371
+ };
372
+ const rows = summary.markdown.split(/\r?\n/u).flatMap(line => {
373
+ const match = line.match(/^[-*]\s+([^:\n]{1,80}):\s*(\S.*)$/u);
374
+ return match && match[2].length <= 1200 ? [{ label: match[1].trim(), text: match[2].trim() }] : [];
375
+ });
376
+ const items = priorities[gate].flatMap(pattern => {
377
+ const matches = rows.filter(row => pattern.test(row.label));
378
+ return matches.length === 1 ? matches : [];
379
+ });
380
+ return { state: 'available', gate, items, markdown: summary.markdown, authorizes: false };
381
+ } catch (error) {
382
+ if (String(error.message).startsWith('approval_summary_')) return null;
383
+ throw error;
384
+ }
385
+ }
386
+
303
387
  // A compact decision brief is a projection of the already validated, source-
304
388
  // authored summary. Missing authored fields stay absent; no agent/UI paraphrase.
305
389
  export function decisionBriefFromSummary(summary, language) {
@@ -388,16 +472,17 @@ export function renderReviewableApproval(root, report, { runId, gate, revisionId
388
472
  const languageName = pack.statusCard[locale.split("-")[0] === "de" ? "languageGerman" : "languageEnglish"];
389
473
  const artifactLabel = german ? "Artefakt" : "Artefact";
390
474
  const requiredHeading = languages.approval_summary_heading ?? `AGDF Approval Summary (${locale}; source=${sourceLanguage})`;
475
+ const sourceIssue = error.message === 'approval_summary_criterion_content_missing';
391
476
  error.recovery = [
392
- `## ${pack.statusCard.summaryRecovery}`,
477
+ `## ${sourceIssue ? (german ? 'PRD-Quellkriterien korrigieren' : 'Correct PRD source criteria') : pack.statusCard.summaryRecovery}`,
393
478
  `Run: \`${runId}\` · Gate: \`${gate}\` · Revision: \`${revisionId}\``,
394
479
  renderApprovalSummaryIssue({ reason: error.message, required_heading: requiredHeading, diagnostics: error.diagnostics }, {
395
480
  path, presentationLanguage: p.presentation_language,
396
481
  }),
397
- pack.operationalValues.approvalSummaryRecovery.replace("{language}", languageName),
398
- `${german ? "Erforderlicher Abschnitt" : "Required section"}: \`${requiredHeading}\``,
482
+ ...(!sourceIssue ? [pack.operationalValues.approvalSummaryRecovery.replace("{language}", languageName),
483
+ `${german ? "Erforderlicher Abschnitt" : "Required section"}: \`${requiredHeading}\``] : []),
399
484
  `${artifactLabel}: [${basename(path)}](<${path}>)`,
400
- pack.operationalValues.completeMissingApprovalSummary,
485
+ ...(!sourceIssue ? [pack.operationalValues.completeMissingApprovalSummary] : []),
401
486
  ].join("\n\n");
402
487
  }
403
488
  throw error;
@@ -22,7 +22,7 @@ import { join } from "node:path";
22
22
  import { runPath } from "./run-state-reader.js";
23
23
  import { readArtefactBindings } from "./artefact-bindings.js";
24
24
  import { exactApprovedArtefacts, readContainedJson, validateBindingProof } from "./artefact-binding-proof.js";
25
- import { SOURCE_GATES, appendSourceRevision, readSourceRevisions, revisionHistoryPrefix, sourceRevisionImpact, sourceRevisionConfirmation, validExpandedRevisionProof } from "./run-source-revisions.js";
25
+ import { SOURCE_GATES, appendSourceRevision, readSourceRevisions, revisionHistoryPrefix, sourceRevisionImpact, sourceRevisionConfirmation, revisionProofProblems } from "./run-source-revisions.js";
26
26
  import { collectRevisionHistory, byteDigest, inspectRevisionHistory, readHistoryBytes } from "./run-revision-history.js";
27
27
  import { commitRunStepLocked, recoverPendingRunStepLocked, pendingRunStepConflictIds, readPendingRunStepJournal, readPendingSourceRevisionJournal } from "./run-step-transaction.js";
28
28
  import { pendingRunStepPath } from "./run-step-pending.js";
@@ -139,27 +139,45 @@ function prepareSourceRevision(root, input) {
139
139
  || boundary.approved.includes(row.type) && state.approvals.get(row.type)?.status !== "approved")) throw revisionError("approved_source_invalid");
140
140
  if (input.commandContext && input.proposalBinding?.path !== evidence) throw revisionError('revision_source_binding_invalid');
141
141
  const boundProposal = input.proposalMaterial ? { validate: () => {} } : input.proposalBinding ? readOperationSource(root, runId, input.proposalBinding) : null;
142
- if (!exactObject(proposal, REVISION_PROPOSAL_FIELDS)
143
- || proposal.target_id !== resolveControlCommandTarget(root).target_id
144
- || proposal.run_id !== runId || proposal.expected_revision_id !== revisionId || proposal.operation_id !== operationId
145
- || proposal.source_gate !== sourceGate || !nonempty(proposal.reason) || !nonempty(proposal.intended_change)
146
- || canonicalJson(proposal.sources) !== canonicalJson(sources)) throw revisionError("revision_proposal_invalid");
142
+ // Name each violated field with its expected binding: these are facts the caller
143
+ // may read anyway, and the proposal can only be corrected when they are known.
144
+ const expected = { target_id: resolveControlCommandTarget(root).target_id, run_id: runId, expected_revision_id: revisionId,
145
+ operation_id: operationId, source_gate: sourceGate, sources };
146
+ const problems = [
147
+ ...(exactObject(proposal, REVISION_PROPOSAL_FIELDS) ? [] : [`fields must be exactly ${REVISION_PROPOSAL_FIELDS.join(", ")}`]),
148
+ ...Object.entries(expected).filter(([key, value]) => canonicalJson(proposal[key] ?? null) !== canonicalJson(value))
149
+ .map(([key, value]) => `${key} must be ${canonicalJson(value)}`),
150
+ ...["reason", "intended_change"].filter(key => !nonempty(proposal[key])).map(key => `${key} must be nonempty text`),
151
+ ];
152
+ if (problems.length) throw revisionError("revision_proposal_invalid",
153
+ `Correct the staged proposal and stage it again; operation_id is the UUID of this source_revision command. ${problems.join("; ")}.`);
147
154
  const assessment = proposal.impact_assessment, index = SOURCE_GATES.indexOf(sourceGate);
148
- if (!exactObject(assessment, REVISION_IMPACT_FIELDS)
149
- || !nonempty(assessment.reviewer) || assessment.earliest_source !== sourceGate || !nonempty(assessment.implementation_evidence)
150
- || !Array.isArray(assessment.unresolved) || assessment.unresolved.length
151
- || !Array.isArray(assessment.upstream) || assessment.upstream.length !== index
152
- || !assessment.upstream.every((row, i) => exactObject(row, REVISION_UPSTREAM_FIELDS)
153
- && nonempty(row.rationale) && canonicalJson({ type: row.type, path: row.path, digest: row.digest }) === canonicalJson(sources[i]))) throw revisionError("source_impact_unresolved", "Resolve the earliest changed source and unchanged upstream rationale with its owner; then regenerate the proposal.");
154
- const analyticalTypes = ["Brownfield Review", "UX Intent Definition"].filter(type => state.artefacts.get(type)?.path);
155
- if (!Array.isArray(assessment.analyses) || assessment.analyses.length !== analyticalTypes.length
156
- || !assessment.analyses.every((row, i) => exactObject(row, REVISION_ANALYSIS_FIELDS)
157
- && row.type === analyticalTypes[i] && row.path === state.artefacts.get(row.type).path
158
- && row.digest === artefactFileDigest(root, row.path) && nonempty(row.reason)
159
- && ["retain", "reassess"].includes(row.disposition) && (sourceGate !== "UR" || row.disposition === "reassess"))) throw revisionError("analysis_applicability_unresolved");
155
+ // Like the binding check above, each rejection names the expected entries.
156
+ const identity = row => canonicalJson({ type: row?.type, path: row?.path, digest: row?.digest });
157
+ const upstream = sources.slice(0, index);
158
+ const impactProblems = [
159
+ ...(exactObject(assessment, REVISION_IMPACT_FIELDS) ? [] : [`impact_assessment fields must be exactly ${REVISION_IMPACT_FIELDS.join(", ")}`]),
160
+ ...(nonempty(assessment?.reviewer) ? [] : ["impact_assessment.reviewer must be nonempty text"]),
161
+ ...(assessment?.earliest_source === sourceGate ? [] : [`impact_assessment.earliest_source must be "${sourceGate}"`]),
162
+ ...(nonempty(assessment?.implementation_evidence) ? [] : ["impact_assessment.implementation_evidence must be nonempty text"]),
163
+ ...(Array.isArray(assessment?.unresolved) && !assessment.unresolved.length ? [] : ["impact_assessment.unresolved must be []"]),
164
+ ...(Array.isArray(assessment?.upstream) && assessment.upstream.length === upstream.length
165
+ && assessment.upstream.every((row, i) => exactObject(row, REVISION_UPSTREAM_FIELDS) && nonempty(row.rationale) && identity(row) === identity(upstream[i]))
166
+ ? [] : [`impact_assessment.upstream must list exactly ${canonicalJson(upstream)} in order, each with a nonempty rationale`]),
167
+ ];
168
+ if (impactProblems.length) throw revisionError("source_impact_unresolved",
169
+ `Resolve the earliest changed source and unchanged upstream rationale with its owner; then regenerate the proposal. ${impactProblems.join("; ")}.`);
170
+ const analyses = ["Brownfield Review", "UX Intent Definition"].filter(type => state.artefacts.get(type)?.path)
171
+ .map(type => ({ type, path: state.artefacts.get(type).path, digest: artefactFileDigest(root, state.artefacts.get(type).path) }));
172
+ const dispositions = sourceGate === "UR" ? ["reassess"] : ["retain", "reassess"];
173
+ if (!Array.isArray(assessment.analyses) || assessment.analyses.length !== analyses.length
174
+ || !assessment.analyses.every((row, i) => exactObject(row, REVISION_ANALYSIS_FIELDS) && identity(row) === identity(analyses[i])
175
+ && nonempty(row.reason) && dispositions.includes(row.disposition)))
176
+ throw revisionError("analysis_applicability_unresolved", `Set impact_assessment.analyses to exactly the registered analyses ${canonicalJson(analyses)} in order, each with a nonempty reason and disposition ${dispositions.join(" or ")}; unregistered analyses are not listed.`);
160
177
  const readArtefact = path => { try { return readHistoryBytes(root, path).toString('utf8'); } catch { return undefined; } };
161
- if (!validExpandedRevisionProof(proposal, state, readArtefact, boundary.initiating_phase))
162
- throw revisionError('revision_impact_proof_invalid', 'Bind concrete changed statements, earliest source, actual phase and every exact quality record; unknown or affected associations require reassessment.');
178
+ const proofProblems = revisionProofProblems(proposal, state, readArtefact, boundary.initiating_phase);
179
+ if (proofProblems.length) throw revisionError('revision_impact_proof_invalid',
180
+ `Bind concrete changed statements, earliest source, actual phase and every exact quality record; unknown or affected associations require reassessment. ${proofProblems.slice(0, 5).join('; ')}.`);
163
181
  const affected = SOURCE_GATES.slice(index);
164
182
  const qualityPaths = proposal.quality_assessment.map(row => row.record.path).filter(Boolean);
165
183
  const history = collectRunRevisionClosure(root, run, state, operationId, boundary.approved, [evidence, ...qualityPaths], { proposalMaterial: input.proposalMaterial });