@kontourai/flow-agents 3.11.0 → 3.12.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 (247) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/build/src/builder-flow-run-adapter.d.ts +1 -0
  3. package/build/src/builder-flow-run-adapter.js +2 -0
  4. package/build/src/builder-flow-runtime.d.ts +5 -0
  5. package/build/src/builder-flow-runtime.js +90 -68
  6. package/build/src/builder-gate-action-envelope.d.ts +151 -0
  7. package/build/src/builder-gate-action-envelope.js +367 -0
  8. package/build/src/cli/public-contracts.d.ts +139 -0
  9. package/build/src/cli/public-contracts.js +37 -0
  10. package/build/src/cli/workflow-sidecar.js +9 -13
  11. package/build/src/cli/workflow.d.ts +1 -0
  12. package/build/src/cli/workflow.js +49 -12
  13. package/build/src/continuation-driver.d.ts +40 -3
  14. package/build/src/continuation-driver.js +361 -412
  15. package/build/src/continuation-persistence.d.ts +4 -0
  16. package/build/src/continuation-persistence.js +296 -0
  17. package/build/src/continuation-validation.d.ts +9 -0
  18. package/build/src/continuation-validation.js +139 -0
  19. package/build/src/flow-kit/action-metadata.d.ts +28 -0
  20. package/build/src/flow-kit/action-metadata.js +162 -0
  21. package/build/src/flow-kit/action-repository-validation.d.ts +16 -0
  22. package/build/src/flow-kit/action-repository-validation.js +237 -0
  23. package/build/src/flow-kit/validate.d.ts +2 -14
  24. package/build/src/flow-kit/validate.js +18 -345
  25. package/build/src/index.d.ts +4 -2
  26. package/build/src/index.js +2 -1
  27. package/dist/base/build/package.json +1 -1
  28. package/dist/base/build/src/builder-flow-run-adapter.d.ts +1 -0
  29. package/dist/base/build/src/builder-flow-run-adapter.js +2 -0
  30. package/dist/base/build/src/builder-flow-runtime.d.ts +5 -0
  31. package/dist/base/build/src/builder-flow-runtime.js +90 -68
  32. package/dist/base/build/src/builder-gate-action-envelope.d.ts +151 -0
  33. package/dist/base/build/src/builder-gate-action-envelope.js +367 -0
  34. package/dist/base/build/src/cli/public-contracts.d.ts +139 -0
  35. package/dist/base/build/src/cli/public-contracts.js +37 -0
  36. package/dist/base/build/src/cli/workflow-sidecar.js +9 -13
  37. package/dist/base/build/src/cli/workflow.d.ts +1 -0
  38. package/dist/base/build/src/cli/workflow.js +49 -12
  39. package/dist/base/build/src/continuation-driver.d.ts +40 -3
  40. package/dist/base/build/src/continuation-driver.js +361 -412
  41. package/dist/base/build/src/continuation-persistence.d.ts +4 -0
  42. package/dist/base/build/src/continuation-persistence.js +296 -0
  43. package/dist/base/build/src/continuation-validation.d.ts +9 -0
  44. package/dist/base/build/src/continuation-validation.js +139 -0
  45. package/dist/base/build/src/flow-kit/action-metadata.d.ts +28 -0
  46. package/dist/base/build/src/flow-kit/action-metadata.js +162 -0
  47. package/dist/base/build/src/flow-kit/action-repository-validation.d.ts +16 -0
  48. package/dist/base/build/src/flow-kit/action-repository-validation.js +237 -0
  49. package/dist/base/build/src/flow-kit/validate.d.ts +2 -14
  50. package/dist/base/build/src/flow-kit/validate.js +18 -345
  51. package/dist/base/build/src/index.d.ts +4 -2
  52. package/dist/base/build/src/index.js +2 -1
  53. package/dist/base/docs/public-workflow-cli.md +41 -5
  54. package/dist/base/docs/spec/builder-flow-runtime.md +117 -0
  55. package/dist/base/evals/integration/test_builder_step_producers.sh +60 -21
  56. package/dist/base/evals/integration/test_bundle_install.sh +15 -15
  57. package/dist/base/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
  58. package/dist/base/install.sh +1 -1
  59. package/dist/base/kits/builder/kit.json +88 -14
  60. package/dist/claude-code/build/package.json +1 -1
  61. package/dist/claude-code/build/src/builder-flow-run-adapter.d.ts +1 -0
  62. package/dist/claude-code/build/src/builder-flow-run-adapter.js +2 -0
  63. package/dist/claude-code/build/src/builder-flow-runtime.d.ts +5 -0
  64. package/dist/claude-code/build/src/builder-flow-runtime.js +90 -68
  65. package/dist/claude-code/build/src/builder-gate-action-envelope.d.ts +151 -0
  66. package/dist/claude-code/build/src/builder-gate-action-envelope.js +367 -0
  67. package/dist/claude-code/build/src/cli/public-contracts.d.ts +139 -0
  68. package/dist/claude-code/build/src/cli/public-contracts.js +37 -0
  69. package/dist/claude-code/build/src/cli/workflow-sidecar.js +9 -13
  70. package/dist/claude-code/build/src/cli/workflow.d.ts +1 -0
  71. package/dist/claude-code/build/src/cli/workflow.js +49 -12
  72. package/dist/claude-code/build/src/continuation-driver.d.ts +40 -3
  73. package/dist/claude-code/build/src/continuation-driver.js +361 -412
  74. package/dist/claude-code/build/src/continuation-persistence.d.ts +4 -0
  75. package/dist/claude-code/build/src/continuation-persistence.js +296 -0
  76. package/dist/claude-code/build/src/continuation-validation.d.ts +9 -0
  77. package/dist/claude-code/build/src/continuation-validation.js +139 -0
  78. package/dist/claude-code/build/src/flow-kit/action-metadata.d.ts +28 -0
  79. package/dist/claude-code/build/src/flow-kit/action-metadata.js +162 -0
  80. package/dist/claude-code/build/src/flow-kit/action-repository-validation.d.ts +16 -0
  81. package/dist/claude-code/build/src/flow-kit/action-repository-validation.js +237 -0
  82. package/dist/claude-code/build/src/flow-kit/validate.d.ts +2 -14
  83. package/dist/claude-code/build/src/flow-kit/validate.js +18 -345
  84. package/dist/claude-code/build/src/index.d.ts +4 -2
  85. package/dist/claude-code/build/src/index.js +2 -1
  86. package/dist/claude-code/docs/public-workflow-cli.md +41 -5
  87. package/dist/claude-code/docs/spec/builder-flow-runtime.md +117 -0
  88. package/dist/claude-code/evals/integration/test_builder_step_producers.sh +60 -21
  89. package/dist/claude-code/evals/integration/test_bundle_install.sh +15 -15
  90. package/dist/claude-code/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
  91. package/dist/claude-code/install.sh +1 -1
  92. package/dist/claude-code/kits/builder/kit.json +88 -14
  93. package/dist/codex/build/package.json +1 -1
  94. package/dist/codex/build/src/builder-flow-run-adapter.d.ts +1 -0
  95. package/dist/codex/build/src/builder-flow-run-adapter.js +2 -0
  96. package/dist/codex/build/src/builder-flow-runtime.d.ts +5 -0
  97. package/dist/codex/build/src/builder-flow-runtime.js +90 -68
  98. package/dist/codex/build/src/builder-gate-action-envelope.d.ts +151 -0
  99. package/dist/codex/build/src/builder-gate-action-envelope.js +367 -0
  100. package/dist/codex/build/src/cli/public-contracts.d.ts +139 -0
  101. package/dist/codex/build/src/cli/public-contracts.js +37 -0
  102. package/dist/codex/build/src/cli/workflow-sidecar.js +9 -13
  103. package/dist/codex/build/src/cli/workflow.d.ts +1 -0
  104. package/dist/codex/build/src/cli/workflow.js +49 -12
  105. package/dist/codex/build/src/continuation-driver.d.ts +40 -3
  106. package/dist/codex/build/src/continuation-driver.js +361 -412
  107. package/dist/codex/build/src/continuation-persistence.d.ts +4 -0
  108. package/dist/codex/build/src/continuation-persistence.js +296 -0
  109. package/dist/codex/build/src/continuation-validation.d.ts +9 -0
  110. package/dist/codex/build/src/continuation-validation.js +139 -0
  111. package/dist/codex/build/src/flow-kit/action-metadata.d.ts +28 -0
  112. package/dist/codex/build/src/flow-kit/action-metadata.js +162 -0
  113. package/dist/codex/build/src/flow-kit/action-repository-validation.d.ts +16 -0
  114. package/dist/codex/build/src/flow-kit/action-repository-validation.js +237 -0
  115. package/dist/codex/build/src/flow-kit/validate.d.ts +2 -14
  116. package/dist/codex/build/src/flow-kit/validate.js +18 -345
  117. package/dist/codex/build/src/index.d.ts +4 -2
  118. package/dist/codex/build/src/index.js +2 -1
  119. package/dist/codex/docs/public-workflow-cli.md +41 -5
  120. package/dist/codex/docs/spec/builder-flow-runtime.md +117 -0
  121. package/dist/codex/evals/integration/test_builder_step_producers.sh +60 -21
  122. package/dist/codex/evals/integration/test_bundle_install.sh +15 -15
  123. package/dist/codex/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
  124. package/dist/codex/install.sh +1 -1
  125. package/dist/codex/kits/builder/kit.json +88 -14
  126. package/dist/kiro/build/package.json +1 -1
  127. package/dist/kiro/build/src/builder-flow-run-adapter.d.ts +1 -0
  128. package/dist/kiro/build/src/builder-flow-run-adapter.js +2 -0
  129. package/dist/kiro/build/src/builder-flow-runtime.d.ts +5 -0
  130. package/dist/kiro/build/src/builder-flow-runtime.js +90 -68
  131. package/dist/kiro/build/src/builder-gate-action-envelope.d.ts +151 -0
  132. package/dist/kiro/build/src/builder-gate-action-envelope.js +367 -0
  133. package/dist/kiro/build/src/cli/public-contracts.d.ts +139 -0
  134. package/dist/kiro/build/src/cli/public-contracts.js +37 -0
  135. package/dist/kiro/build/src/cli/workflow-sidecar.js +9 -13
  136. package/dist/kiro/build/src/cli/workflow.d.ts +1 -0
  137. package/dist/kiro/build/src/cli/workflow.js +49 -12
  138. package/dist/kiro/build/src/continuation-driver.d.ts +40 -3
  139. package/dist/kiro/build/src/continuation-driver.js +361 -412
  140. package/dist/kiro/build/src/continuation-persistence.d.ts +4 -0
  141. package/dist/kiro/build/src/continuation-persistence.js +296 -0
  142. package/dist/kiro/build/src/continuation-validation.d.ts +9 -0
  143. package/dist/kiro/build/src/continuation-validation.js +139 -0
  144. package/dist/kiro/build/src/flow-kit/action-metadata.d.ts +28 -0
  145. package/dist/kiro/build/src/flow-kit/action-metadata.js +162 -0
  146. package/dist/kiro/build/src/flow-kit/action-repository-validation.d.ts +16 -0
  147. package/dist/kiro/build/src/flow-kit/action-repository-validation.js +237 -0
  148. package/dist/kiro/build/src/flow-kit/validate.d.ts +2 -14
  149. package/dist/kiro/build/src/flow-kit/validate.js +18 -345
  150. package/dist/kiro/build/src/index.d.ts +4 -2
  151. package/dist/kiro/build/src/index.js +2 -1
  152. package/dist/kiro/docs/public-workflow-cli.md +41 -5
  153. package/dist/kiro/docs/spec/builder-flow-runtime.md +117 -0
  154. package/dist/kiro/evals/integration/test_builder_step_producers.sh +60 -21
  155. package/dist/kiro/evals/integration/test_bundle_install.sh +15 -15
  156. package/dist/kiro/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
  157. package/dist/kiro/install.sh +1 -1
  158. package/dist/kiro/kits/builder/kit.json +88 -14
  159. package/dist/opencode/build/package.json +1 -1
  160. package/dist/opencode/build/src/builder-flow-run-adapter.d.ts +1 -0
  161. package/dist/opencode/build/src/builder-flow-run-adapter.js +2 -0
  162. package/dist/opencode/build/src/builder-flow-runtime.d.ts +5 -0
  163. package/dist/opencode/build/src/builder-flow-runtime.js +90 -68
  164. package/dist/opencode/build/src/builder-gate-action-envelope.d.ts +151 -0
  165. package/dist/opencode/build/src/builder-gate-action-envelope.js +367 -0
  166. package/dist/opencode/build/src/cli/public-contracts.d.ts +139 -0
  167. package/dist/opencode/build/src/cli/public-contracts.js +37 -0
  168. package/dist/opencode/build/src/cli/workflow-sidecar.js +9 -13
  169. package/dist/opencode/build/src/cli/workflow.d.ts +1 -0
  170. package/dist/opencode/build/src/cli/workflow.js +49 -12
  171. package/dist/opencode/build/src/continuation-driver.d.ts +40 -3
  172. package/dist/opencode/build/src/continuation-driver.js +361 -412
  173. package/dist/opencode/build/src/continuation-persistence.d.ts +4 -0
  174. package/dist/opencode/build/src/continuation-persistence.js +296 -0
  175. package/dist/opencode/build/src/continuation-validation.d.ts +9 -0
  176. package/dist/opencode/build/src/continuation-validation.js +139 -0
  177. package/dist/opencode/build/src/flow-kit/action-metadata.d.ts +28 -0
  178. package/dist/opencode/build/src/flow-kit/action-metadata.js +162 -0
  179. package/dist/opencode/build/src/flow-kit/action-repository-validation.d.ts +16 -0
  180. package/dist/opencode/build/src/flow-kit/action-repository-validation.js +237 -0
  181. package/dist/opencode/build/src/flow-kit/validate.d.ts +2 -14
  182. package/dist/opencode/build/src/flow-kit/validate.js +18 -345
  183. package/dist/opencode/build/src/index.d.ts +4 -2
  184. package/dist/opencode/build/src/index.js +2 -1
  185. package/dist/opencode/docs/public-workflow-cli.md +41 -5
  186. package/dist/opencode/docs/spec/builder-flow-runtime.md +117 -0
  187. package/dist/opencode/evals/integration/test_builder_step_producers.sh +60 -21
  188. package/dist/opencode/evals/integration/test_bundle_install.sh +15 -15
  189. package/dist/opencode/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
  190. package/dist/opencode/install.sh +1 -1
  191. package/dist/opencode/kits/builder/kit.json +88 -14
  192. package/dist/pi/build/package.json +1 -1
  193. package/dist/pi/build/src/builder-flow-run-adapter.d.ts +1 -0
  194. package/dist/pi/build/src/builder-flow-run-adapter.js +2 -0
  195. package/dist/pi/build/src/builder-flow-runtime.d.ts +5 -0
  196. package/dist/pi/build/src/builder-flow-runtime.js +90 -68
  197. package/dist/pi/build/src/builder-gate-action-envelope.d.ts +151 -0
  198. package/dist/pi/build/src/builder-gate-action-envelope.js +367 -0
  199. package/dist/pi/build/src/cli/public-contracts.d.ts +139 -0
  200. package/dist/pi/build/src/cli/public-contracts.js +37 -0
  201. package/dist/pi/build/src/cli/workflow-sidecar.js +9 -13
  202. package/dist/pi/build/src/cli/workflow.d.ts +1 -0
  203. package/dist/pi/build/src/cli/workflow.js +49 -12
  204. package/dist/pi/build/src/continuation-driver.d.ts +40 -3
  205. package/dist/pi/build/src/continuation-driver.js +361 -412
  206. package/dist/pi/build/src/continuation-persistence.d.ts +4 -0
  207. package/dist/pi/build/src/continuation-persistence.js +296 -0
  208. package/dist/pi/build/src/continuation-validation.d.ts +9 -0
  209. package/dist/pi/build/src/continuation-validation.js +139 -0
  210. package/dist/pi/build/src/flow-kit/action-metadata.d.ts +28 -0
  211. package/dist/pi/build/src/flow-kit/action-metadata.js +162 -0
  212. package/dist/pi/build/src/flow-kit/action-repository-validation.d.ts +16 -0
  213. package/dist/pi/build/src/flow-kit/action-repository-validation.js +237 -0
  214. package/dist/pi/build/src/flow-kit/validate.d.ts +2 -14
  215. package/dist/pi/build/src/flow-kit/validate.js +18 -345
  216. package/dist/pi/build/src/index.d.ts +4 -2
  217. package/dist/pi/build/src/index.js +2 -1
  218. package/dist/pi/docs/public-workflow-cli.md +41 -5
  219. package/dist/pi/docs/spec/builder-flow-runtime.md +117 -0
  220. package/dist/pi/evals/integration/test_builder_step_producers.sh +60 -21
  221. package/dist/pi/evals/integration/test_bundle_install.sh +15 -15
  222. package/dist/pi/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
  223. package/dist/pi/install.sh +1 -1
  224. package/dist/pi/kits/builder/kit.json +88 -14
  225. package/docs/public-workflow-cli.md +41 -5
  226. package/docs/spec/builder-flow-runtime.md +117 -0
  227. package/evals/integration/test_builder_step_producers.sh +60 -21
  228. package/evals/integration/test_bundle_install.sh +15 -15
  229. package/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
  230. package/kits/builder/kit.json +88 -14
  231. package/package.json +1 -1
  232. package/src/builder-flow-run-adapter.ts +3 -0
  233. package/src/builder-flow-runtime.ts +73 -46
  234. package/src/builder-gate-action-envelope.ts +529 -0
  235. package/src/cli/builder-flow-runtime.test.mjs +287 -58
  236. package/src/cli/continuation-driver.test.mjs +527 -24
  237. package/src/cli/kit-metadata-security.test.mjs +161 -8
  238. package/src/cli/public-contracts.ts +41 -0
  239. package/src/cli/workflow-sidecar.ts +9 -13
  240. package/src/cli/workflow.ts +48 -12
  241. package/src/continuation-driver.ts +466 -378
  242. package/src/continuation-persistence.ts +228 -0
  243. package/src/continuation-validation.ts +107 -0
  244. package/src/flow-kit/action-metadata.ts +155 -0
  245. package/src/flow-kit/action-repository-validation.ts +192 -0
  246. package/src/flow-kit/validate.ts +19 -326
  247. package/src/index.ts +17 -0
@@ -190,6 +190,41 @@ test_produce_claim() {
190
190
  || _fail "$label: bundle missing or incorrect $expected_claim_type claim"
191
191
  }
192
192
 
193
+ test_operation_claim_rejection() {
194
+ local label="$1" step="$2" expectation="$3" expected_claim_type="$4"
195
+ echo ""
196
+ echo "=== OPERATION REJECTION: $label ==="
197
+
198
+ local slug
199
+ slug="$(echo "operation-$step-$expectation" | tr '/' '-' | tr '.' '-')"
200
+ local aroot="$TMP/$slug/.kontourai/flow-agents"
201
+ setup_session_for_produce "$aroot" "$slug" "$step"
202
+ local artifact="$aroot/$slug/publish-change.result.json"
203
+ printf '{"provider":"fixture","repository":"acme/builder","number":1,"url":"https://example.test/acme/builder/pull/1","head_ref":"fixture","base_ref":"main"}\n' > "$artifact"
204
+
205
+ if flow_agents_node "workflow-sidecar" record-gate-claim "$aroot/$slug" \
206
+ --status pass \
207
+ --summary "Locally authored operation result must not self-complete." \
208
+ --expectation "$expectation" \
209
+ --evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$artifact\",\"summary\":\"Locally authored provider-shaped result.\"}" \
210
+ --timestamp "2026-06-26T00:02:00Z" >/dev/null 2>&1; then
211
+ _fail "$label: record-gate-claim accepted operation self-completion"
212
+ else
213
+ _pass "$label: record-gate-claim rejects operation self-completion"
214
+ fi
215
+
216
+ node -e "
217
+ const fs = require('fs');
218
+ const current = JSON.parse(fs.readFileSync('$aroot/current.json', 'utf8'));
219
+ if (current.active_step_id !== '$step') throw new Error('expected active step $step, got ' + current.active_step_id);
220
+ const bundleFile = '$aroot/$slug/trust.bundle';
221
+ const bundle = fs.existsSync(bundleFile) ? JSON.parse(fs.readFileSync(bundleFile, 'utf8')) : { claims: [] };
222
+ if ((bundle.claims || []).some((claim) => claim.claimType === '$expected_claim_type')) throw new Error('operation-bound claim was recorded');
223
+ " 2>/dev/null \
224
+ && _pass "$label: no operation claim is recorded and pr-open remains active" \
225
+ || _fail "$label: operation rejection recorded a claim or changed the active step"
226
+ }
227
+
193
228
  # ─── Test: tampered bundle at given step BLOCKS ───────────────────────────────
194
229
  test_tamper_blocks() {
195
230
  local label="$1" step="$2" claim_type="$3" subject_type="$4"
@@ -376,11 +411,11 @@ test_tamper_blocks \
376
411
  "builder.design-probe.decisions" \
377
412
  "design-probe" "builder.design-probe.decisions" "decision"
378
413
 
379
- # Claim 4: builder.pr-open.pull-request
380
- test_produce_claim \
414
+ # Claim 4: builder.pr-open.pull-request is external-only and generic claims must reject it.
415
+ test_operation_claim_rejection \
381
416
  "builder.pr-open.pull-request" \
382
417
  "pr-open" "pull-request-opened" \
383
- "builder.pr-open.pull-request" "pull-request"
418
+ "builder.pr-open.pull-request"
384
419
  test_tamper_blocks \
385
420
  "builder.pr-open.pull-request" \
386
421
  "pr-open" "builder.pr-open.pull-request" "pull-request"
@@ -405,17 +440,17 @@ test_tamper_blocks \
405
440
 
406
441
  # ─── Public CLI happy path + route-back ─────────────────────────────────────
407
442
  echo ""
408
- echo "=== PUBLIC CLI: complete canonical skill/operation path ==="
443
+ echo "=== PUBLIC CLI: canonical skill path and external operation boundary ==="
409
444
  flow_agents_build_ts || _fail "public CLI fixture build failed"
410
445
  PUBLIC_ROOT="$TMP/public/.kontourai/flow-agents"
411
446
  PUBLIC_SESSION="$PUBLIC_ROOT/acme-builder-901"
412
447
 
413
448
  public_flow() {
414
- CODEX_SESSION_ID=builder-public-producers node "$ROOT/build/src/cli.js" workflow "$@"
449
+ env -u CODEX_THREAD_ID CODEX_SESSION_ID=builder-public-producers node "$ROOT/build/src/cli.js" workflow "$@"
415
450
  }
416
451
 
417
452
  public_review() {
418
- CODEX_SESSION_ID=builder-public-reviewer node "$ROOT/build/src/cli.js" workflow "$@"
453
+ env -u CODEX_THREAD_ID CODEX_SESSION_ID=builder-public-reviewer node "$ROOT/build/src/cli.js" workflow "$@"
419
454
  }
420
455
 
421
456
  assert_public_step() {
@@ -578,25 +613,29 @@ else
578
613
  fi
579
614
  assert_public_step "merge-ready" "evidence-gate" ""
580
615
  record_public_expectation "merge-readiness"
581
- assert_public_step "pr-open" "" "publish-change"
582
- record_public_expectation "pull-request-opened"
583
- assert_public_step "merge-ready-ci" "release-readiness" ""
584
- record_public_expectation "ci-merge-readiness"
585
- assert_public_step "learn" "learning-review" ""
586
- record_public_expectation "decision-evidence"
587
- assert_public_step "learn" "learning-review" "" "active-or-blocked"
588
- record_public_expectation "learning-evidence"
589
- if node - "$PUBLIC_SESSION/trust.bundle" <<'NODE'
590
- const fs = require('node:fs');
591
- const bundle = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
592
- if (!bundle.claims.some((claim) => claim.claimType === 'builder.learn.evidence' && claim.subjectType === 'release' && claim.status === 'verified')) process.exit(1);
616
+ assert_public_step "pr-open" "" "publish-change" "active-or-blocked"
617
+ PUBLIC_PR_OPEN_REPORT="$(public_flow status --session-dir "$PUBLIC_SESSION" --json 2>/dev/null)"
618
+ if node - "$PUBLIC_PR_OPEN_REPORT" <<'NODE'
619
+ const report = JSON.parse(process.argv[2]);
620
+ const capability = report.next_action?.external_capability;
621
+ if (report.current_step !== 'pr-open' || report.next_action?.status !== 'blocked') process.exit(1);
622
+ if (capability?.operation !== 'publish-change' || capability?.completion !== 'external_verification_required') process.exit(2);
593
623
  NODE
594
624
  then
595
- _pass "learning-review records verified learning.json evidence"
625
+ _pass "pr-open projects the external publish-change capability block"
626
+ else
627
+ _fail "pr-open did not expose the required external capability block: $PUBLIC_PR_OPEN_REPORT"
628
+ fi
629
+ node - "$PUBLIC_SESSION/publish-change.result.json" <<'NODE'
630
+ const fs = require('node:fs');
631
+ fs.writeFileSync(process.argv[2], JSON.stringify({ provider: 'fixture', repository: 'acme/builder', number: 901, url: 'https://example.test/acme/builder/pull/901', head_ref: 'fixture', base_ref: 'main' }));
632
+ NODE
633
+ if public_flow evidence --session-dir "$PUBLIC_SESSION" --expectation pull-request-opened --status pass --summary "Locally authored result must not self-complete publish-change." --evidence-ref-json "{\"kind\":\"artifact\",\"file\":\".kontourai/flow-agents/$(basename "$PUBLIC_SESSION")/publish-change.result.json\",\"summary\":\"Locally authored provider-shaped result.\"}" >/dev/null 2>&1; then
634
+ _fail "generic workflow evidence accepted operation self-completion"
596
635
  else
597
- _fail "learning-review did not record durable learning.json evidence in trust.bundle"
636
+ _pass "generic workflow evidence rejects operation self-completion"
598
637
  fi
599
- assert_public_step "learn" "" "" "completed"
638
+ assert_public_step "pr-open" "" "publish-change" "active-or-blocked"
600
639
 
601
640
  echo ""
602
641
  echo "=== PUBLIC CLI: failed verify route-back remains canonical ==="
@@ -1061,18 +1061,6 @@ NODE
1061
1061
  package_flow evidence --session-dir "$PACKAGE_SESSION" --expectation merge-readiness --status pass \
1062
1062
  --summary "Packed fixture records the declared merge-readiness artifact." \
1063
1063
  --evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$PACKAGE_SESSION/acme-builder-901--evidence-gate.md\",\"summary\":\"Durable merge-readiness artifact.\"}" >/dev/null \
1064
- && package_flow evidence --session-dir "$PACKAGE_SESSION" --expectation pull-request-opened --status pass \
1065
- --summary "Packed fixture records the declared release artifact." \
1066
- --evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$PACKAGE_SESSION/release.json\",\"summary\":\"Durable release artifact.\"}" >/dev/null \
1067
- && package_flow evidence --session-dir "$PACKAGE_SESSION" --expectation ci-merge-readiness --status pass \
1068
- --summary "Packed fixture records the declared CI readiness artifact." \
1069
- --evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$PACKAGE_SESSION/release.json\",\"summary\":\"Durable CI readiness artifact.\"}" >/dev/null \
1070
- && package_flow evidence --session-dir "$PACKAGE_SESSION" --expectation decision-evidence --status pass \
1071
- --summary "Packed fixture records the declared learning decision artifact." \
1072
- --evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$PACKAGE_SESSION/learning.json\",\"summary\":\"Durable learning decision artifact.\"}" >/dev/null \
1073
- && package_flow evidence --session-dir "$PACKAGE_SESSION" --expectation learning-evidence --status pass \
1074
- --summary "Packed fixture records the declared learning evidence artifact." \
1075
- --evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$PACKAGE_SESSION/learning.json\",\"summary\":\"Durable learning evidence artifact.\"}" >/dev/null \
1076
1064
  && node - "$PACKAGE_SESSION" <<'NODE' &&
1077
1065
  const fs = require('node:fs');
1078
1066
  const path = require('node:path');
@@ -1087,14 +1075,26 @@ const requiredTypes = [
1087
1075
  'builder.execute.scope',
1088
1076
  'builder.verify.tests',
1089
1077
  'builder.merge-ready.readiness',
1090
- 'builder.learn.decisions',
1091
- 'builder.learn.evidence',
1092
1078
  ];
1093
1079
  const missingTypes = requiredTypes.filter((type) => !types.has(type));
1094
1080
  if (missingTypes.length > 0) {
1095
- console.error(`missing verified public workflow claims: ${missingTypes.join(', ')}`);
1081
+ console.error(`missing verified pre-operation workflow claims: ${missingTypes.join(', ')}`);
1096
1082
  process.exit(1);
1097
1083
  }
1084
+ fs.writeFileSync(path.join(session, 'publish-change.result.json'), JSON.stringify({ provider: 'fixture', repository: 'acme/builder', number: 901, url: 'https://example.test/acme/builder/pull/901', head_ref: 'fixture', base_ref: 'main' }));
1085
+ NODE
1086
+ ! package_flow evidence --session-dir "$PACKAGE_SESSION" --expectation pull-request-opened --status pass \
1087
+ --summary "Locally authored publish-change result must not self-complete." \
1088
+ --evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$PACKAGE_SESSION/publish-change.result.json\",\"summary\":\"Locally authored provider-shaped result.\"}" >/dev/null 2>&1 \
1089
+ && node - "$PACKAGE_SESSION" "$PACKAGE_PROJECT" <<'NODE' &&
1090
+ const fs = require('node:fs');
1091
+ const path = require('node:path');
1092
+ const [session, project] = process.argv.slice(2);
1093
+ const state = JSON.parse(fs.readFileSync(path.join(session, 'state.json'), 'utf8'));
1094
+ const flow = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow', 'runs', path.basename(session), 'state.json'), 'utf8'));
1095
+ const bundle = JSON.parse(fs.readFileSync(path.join(session, 'trust.bundle'), 'utf8'));
1096
+ if (state.flow_run?.current_step !== 'pr-open' || flow.current_step !== 'pr-open' || state.next_action?.status !== 'blocked') process.exit(1);
1097
+ if ((bundle.claims || []).some((claim) => claim.claimType === 'builder.pr-open.pull-request')) process.exit(2);
1098
1098
  NODE
1099
1099
  printf 'Selected Work Item: acme/builder#902\n' > "$PACKAGE_LIFECYCLE_SESSION/acme-builder-902--pull-work.md" \
1100
1100
  && package_flow start --artifact-root "$PACKAGE_PROJECT/.kontourai/flow-agents" \
@@ -206,7 +206,7 @@ node -e "
206
206
  || _fail "bundle missing selected-work claim or declared durable artifact evidence"
207
207
 
208
208
  echo ""
209
- echo "=== 4b. composed publish-learn gate claim emits builder.pr-open.pull-request ==="
209
+ echo "=== 4b. composed publish-learn operation cannot self-complete through record-gate-claim ==="
210
210
 
211
211
  COMPOSED_ROOT="$TMP/composed-gate-claim-project/.kontourai/flow-agents"
212
212
  mkdir -p "$COMPOSED_ROOT"
@@ -237,9 +237,9 @@ if flow_agents_node "workflow-sidecar" record-gate-claim "$COMPOSED_ROOT/compose
237
237
  --expectation pull-request-opened \
238
238
  --evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$COMPOSED_ARTIFACT\",\"summary\":\"Declared durable release artifact for pull-request-opened.\"}" \
239
239
  --timestamp "2026-06-26T00:01:00Z" >/dev/null 2>&1; then
240
- _pass "record-gate-claim exits 0 at composed pr-open step"
240
+ _fail "record-gate-claim accepted composed operation self-completion"
241
241
  else
242
- _fail "record-gate-claim failed at composed pr-open step"
242
+ _pass "record-gate-claim rejects composed operation self-completion"
243
243
  fi
244
244
 
245
245
  node -e "
@@ -247,32 +247,19 @@ node -e "
247
247
  const current = JSON.parse(fs.readFileSync('$COMPOSED_ROOT/current.json', 'utf8'));
248
248
  if (current.active_flow_id !== 'builder.build') throw new Error('expected active_flow_id=builder.build, got ' + current.active_flow_id);
249
249
  if (current.active_step_id !== 'pr-open') throw new Error('expected active_step_id=pr-open, got ' + current.active_step_id);
250
- const bundle = JSON.parse(fs.readFileSync('$COMPOSED_ROOT/composed-gate-claim/trust.bundle', 'utf8'));
251
- const target = (bundle.claims || []).find(c => c.claimType === 'builder.pr-open.pull-request');
252
- if (!target) {
253
- console.error('no builder.pr-open.pull-request claim found; claims:', (bundle.claims||[]).map(c=>c.claimType).join(', '));
254
- process.exit(1);
255
- }
256
- if (target.subjectType !== 'pull-request') {
257
- console.error('expected subjectType=pull-request, got', target.subjectType);
258
- process.exit(1);
259
- }
260
- if (target.status !== 'verified') {
261
- console.error('expected status=verified, got', target.status);
250
+ const bundleFile = '$COMPOSED_ROOT/composed-gate-claim/trust.bundle';
251
+ const bundle = fs.existsSync(bundleFile) ? JSON.parse(fs.readFileSync(bundleFile, 'utf8')) : { claims: [] };
252
+ if ((bundle.claims || []).some(c => c.claimType === 'builder.pr-open.pull-request')) {
253
+ console.error('operation-bound claim was recorded despite generic producer rejection');
262
254
  process.exit(1);
263
255
  }
264
- const expectedArtifact = '.kontourai/flow-agents/composed-gate-claim/release.json';
265
256
  if (!fs.existsSync('$COMPOSED_ARTIFACT')) {
266
257
  console.error('missing declared durable pr-open artifact:', '$COMPOSED_ARTIFACT');
267
258
  process.exit(1);
268
259
  }
269
- if (!target.metadata?.artifact_refs?.some(ref => ref.kind === 'artifact' && ref.file === expectedArtifact)) {
270
- console.error('pr-open claim does not cite declared artifact:', JSON.stringify(target.metadata?.artifact_refs));
271
- process.exit(1);
272
- }
273
260
  " 2>/dev/null \
274
- && _pass "composed bundle contains builder.pr-open.pull-request with declared durable artifact evidence" \
275
- || _fail "composed bundle missing pr-open claim or declared durable artifact evidence"
261
+ && _pass "composed operation rejection leaves pr-open active with no claim or advancement" \
262
+ || _fail "composed operation rejection changed pr-open state or recorded a claim"
276
263
 
277
264
  # ─── Tamper-blocks: stored verified + evidence fail → BLOCK (exit 2) ─────────
278
265
  echo ""
@@ -72,7 +72,7 @@ if [[ ! -e "$DEST/AGENTS.md" && ! -L "$DEST/AGENTS.md" ]]; then
72
72
  rm -f "$instruction_tmp"
73
73
  fi
74
74
  if command -v node >/dev/null 2>&1; then
75
- node "$DEST/scripts/install-merge.js" --stamp-only --version "3.11.0" --install-record "$DEST/.flow-agents/install.json" --runtime "pi" || true
75
+ node "$DEST/scripts/install-merge.js" --stamp-only --version "3.12.0" --install-record "$DEST/.flow-agents/install.json" --runtime "pi" || true
76
76
  fi
77
77
  if [[ ${#CONSOLE_CONFIG_ARGS[@]} -gt 0 || -n "${FLOW_AGENTS_TELEMETRY_SINK:-}" || -n "${FLOW_AGENTS_TELEMETRY_SINKS:-}" || -n "${FLOW_AGENTS_CONSOLE_URL:-}" || -n "${CONSOLE_TELEMETRY_URL:-}" || -n "${CONSOLE_URL:-}" || -n "${FLOW_AGENTS_CONSOLE_TOKEN_FILE:-}" || -n "${CONSOLE_TELEMETRY_TOKEN_FILE:-}" ]]; then
78
78
  bash "$DEST/scripts/telemetry/install-console-config.sh" "$DEST/scripts/telemetry/telemetry.conf" "${CONSOLE_CONFIG_ARGS[@]}"
@@ -49,87 +49,161 @@
49
49
  "flow_id": "builder.build",
50
50
  "step_id": "pull-work",
51
51
  "skills": ["pull-work"],
52
- "expectation_ids": ["selected-work"]
52
+ "implementation_allowed": false,
53
+ "artifacts": ["<slug>--pull-work.md", "trust.bundle#selected-work"],
54
+ "expectation_ids": ["selected-work"],
55
+ "expectation_bindings": [{ "expectation_id": "selected-work", "interface": "workflow.evidence" }],
56
+ "artifact_bindings": [{ "artifact": "<slug>--pull-work.md", "expectation_ids": ["selected-work"] }, { "artifact": "trust.bundle#selected-work", "expectation_ids": ["selected-work"] }]
53
57
  },
54
58
  {
55
59
  "flow_id": "builder.build",
56
60
  "step_id": "design-probe",
57
61
  "skills": ["pickup-probe"],
58
- "expectation_ids": ["pickup-probe-readiness", "probe-decisions-or-accepted-gaps"]
62
+ "implementation_allowed": false,
63
+ "artifacts": ["<slug>--pull-work.md", "trust.bundle#pickup-probe"],
64
+ "expectation_ids": ["pickup-probe-readiness", "probe-decisions-or-accepted-gaps"],
65
+ "expectation_bindings": [
66
+ { "expectation_id": "pickup-probe-readiness", "interface": "workflow.evidence" },
67
+ { "expectation_id": "probe-decisions-or-accepted-gaps", "interface": "workflow.evidence" }
68
+ ],
69
+ "artifact_bindings": [{ "artifact": "<slug>--pull-work.md", "expectation_ids": ["pickup-probe-readiness", "probe-decisions-or-accepted-gaps"] }, { "artifact": "trust.bundle#pickup-probe", "expectation_ids": ["pickup-probe-readiness", "probe-decisions-or-accepted-gaps"] }]
59
70
  },
60
71
  {
61
72
  "flow_id": "builder.build",
62
73
  "step_id": "plan",
63
74
  "skills": ["plan-work"],
64
- "expectation_ids": ["implementation-plan"]
75
+ "implementation_allowed": false,
76
+ "artifacts": ["<slug>--plan-work.md", "acceptance.json", "handoff.json", "trust.bundle#implementation-plan"],
77
+ "expectation_ids": ["implementation-plan"],
78
+ "expectation_bindings": [{ "expectation_id": "implementation-plan", "interface": "workflow.evidence" }],
79
+ "artifact_bindings": [{ "artifact": "<slug>--plan-work.md", "expectation_ids": ["implementation-plan"] }, { "artifact": "acceptance.json", "expectation_ids": ["implementation-plan"] }, { "artifact": "handoff.json", "expectation_ids": ["implementation-plan"] }, { "artifact": "trust.bundle#implementation-plan", "expectation_ids": ["implementation-plan"] }]
65
80
  },
66
81
  {
67
82
  "flow_id": "builder.build",
68
83
  "step_id": "execute",
69
84
  "skills": ["execute-plan"],
70
- "expectation_ids": ["implementation-scope"]
85
+ "implementation_allowed": true,
86
+ "artifacts": ["<slug>--deliver.md", "state.json", "trust.bundle#implementation-scope"],
87
+ "expectation_ids": ["implementation-scope"],
88
+ "expectation_bindings": [{ "expectation_id": "implementation-scope", "interface": "workflow.evidence" }],
89
+ "artifact_bindings": [{ "artifact": "<slug>--deliver.md", "expectation_ids": ["implementation-scope"] }, { "artifact": "state.json", "expectation_ids": [] }, { "artifact": "trust.bundle#implementation-scope", "expectation_ids": ["implementation-scope"] }]
71
90
  },
72
91
  {
73
92
  "flow_id": "builder.build",
74
93
  "step_id": "verify",
75
94
  "skills": ["review-work", "verify-work"],
76
- "expectation_ids": ["clean-critique", "acceptance-criteria", "tests-evidence", "policy-compliance"]
95
+ "implementation_allowed": false,
96
+ "artifacts": ["trust.bundle#critique", "trust.bundle#acceptance-criteria", "trust.bundle#tests-evidence", "trust.bundle#policy-compliance"],
97
+ "expectation_ids": ["clean-critique", "acceptance-criteria", "tests-evidence", "policy-compliance"],
98
+ "expectation_bindings": [
99
+ { "expectation_id": "clean-critique", "interface": "workflow.critique" },
100
+ { "expectation_id": "acceptance-criteria", "interface": "workflow.evidence" },
101
+ { "expectation_id": "tests-evidence", "interface": "workflow.evidence" },
102
+ { "expectation_id": "policy-compliance", "interface": "workflow.evidence" }
103
+ ],
104
+ "artifact_bindings": [{ "artifact": "trust.bundle#critique", "expectation_ids": ["clean-critique"] }, { "artifact": "trust.bundle#acceptance-criteria", "expectation_ids": ["acceptance-criteria"] }, { "artifact": "trust.bundle#tests-evidence", "expectation_ids": ["tests-evidence"] }, { "artifact": "trust.bundle#policy-compliance", "expectation_ids": ["policy-compliance"] }]
77
105
  },
78
106
  {
79
107
  "flow_id": "builder.build",
80
108
  "step_id": "merge-ready",
81
109
  "skills": ["evidence-gate"],
82
- "expectation_ids": ["merge-readiness"]
110
+ "implementation_allowed": false,
111
+ "artifacts": ["<slug>--evidence-gate.md", "trust.bundle#merge-readiness"],
112
+ "expectation_ids": ["merge-readiness"],
113
+ "expectation_bindings": [{ "expectation_id": "merge-readiness", "interface": "workflow.evidence" }],
114
+ "artifact_bindings": [{ "artifact": "<slug>--evidence-gate.md", "expectation_ids": ["merge-readiness"] }, { "artifact": "trust.bundle#merge-readiness", "expectation_ids": ["merge-readiness"] }]
83
115
  },
84
116
  {
85
117
  "flow_id": "builder.build",
86
118
  "step_id": "pr-open",
87
119
  "skills": [],
88
120
  "operations": ["publish-change"],
121
+ "implementation_allowed": false,
89
122
  "expectation_ids": ["pull-request-opened"],
90
- "artifacts": ["release.json"]
123
+ "artifacts": ["publish-change.result.json"],
124
+ "expectation_bindings": [{ "expectation_id": "pull-request-opened", "interface": "operation", "operation": "publish-change" }],
125
+ "artifact_bindings": [{ "artifact": "publish-change.result.json", "expectation_ids": ["pull-request-opened"] }]
91
126
  },
92
127
  {
93
128
  "flow_id": "builder.build",
94
129
  "step_id": "merge-ready-ci",
95
130
  "skills": ["release-readiness"],
96
- "expectation_ids": ["ci-merge-readiness"]
131
+ "implementation_allowed": false,
132
+ "artifacts": ["release.json", "trust.bundle#ci-merge-readiness"],
133
+ "expectation_ids": ["ci-merge-readiness"],
134
+ "expectation_bindings": [{ "expectation_id": "ci-merge-readiness", "interface": "workflow.evidence" }],
135
+ "artifact_bindings": [{ "artifact": "release.json", "expectation_ids": ["ci-merge-readiness"] }, { "artifact": "trust.bundle#ci-merge-readiness", "expectation_ids": ["ci-merge-readiness"] }]
97
136
  },
98
137
  {
99
138
  "flow_id": "builder.build",
100
139
  "step_id": "learn",
101
140
  "skills": ["learning-review"],
102
- "expectation_ids": ["decision-evidence", "learning-evidence"]
141
+ "implementation_allowed": false,
142
+ "artifacts": ["learning.json", "trust.bundle#decision-evidence", "trust.bundle#learning-evidence"],
143
+ "expectation_ids": ["decision-evidence", "learning-evidence"],
144
+ "expectation_bindings": [
145
+ { "expectation_id": "decision-evidence", "interface": "workflow.evidence" },
146
+ { "expectation_id": "learning-evidence", "interface": "workflow.evidence" }
147
+ ],
148
+ "artifact_bindings": [{ "artifact": "learning.json", "expectation_ids": ["decision-evidence", "learning-evidence"] }, { "artifact": "trust.bundle#decision-evidence", "expectation_ids": ["decision-evidence"] }, { "artifact": "trust.bundle#learning-evidence", "expectation_ids": ["learning-evidence"] }]
103
149
  },
104
150
  {
105
151
  "flow_id": "builder.build",
106
152
  "step_id": "done",
107
153
  "skills": [],
108
- "expectation_ids": []
154
+ "implementation_allowed": false,
155
+ "artifacts": [],
156
+ "expectation_ids": [],
157
+ "expectation_bindings": [],
158
+ "artifact_bindings": []
109
159
  },
110
160
  {
111
161
  "flow_id": "builder.shape",
112
162
  "step_id": "shape",
113
163
  "skills": ["idea-to-backlog"],
114
- "expectation_ids": ["shaped-problem", "shaped-outcome", "shaped-constraints", "shaped-non-goals", "shaped-success", "shaped-risk", "open-decisions"]
164
+ "implementation_allowed": false,
165
+ "artifacts": ["<slug>--idea-to-backlog.md", "trust.bundle#builder.shape"],
166
+ "expectation_ids": ["shaped-problem", "shaped-outcome", "shaped-constraints", "shaped-non-goals", "shaped-success", "shaped-risk", "open-decisions"],
167
+ "expectation_bindings": [
168
+ { "expectation_id": "shaped-problem", "interface": "workflow.evidence" },
169
+ { "expectation_id": "shaped-outcome", "interface": "workflow.evidence" },
170
+ { "expectation_id": "shaped-constraints", "interface": "workflow.evidence" },
171
+ { "expectation_id": "shaped-non-goals", "interface": "workflow.evidence" },
172
+ { "expectation_id": "shaped-success", "interface": "workflow.evidence" },
173
+ { "expectation_id": "shaped-risk", "interface": "workflow.evidence" },
174
+ { "expectation_id": "open-decisions", "interface": "workflow.evidence" }
175
+ ],
176
+ "artifact_bindings": [{ "artifact": "<slug>--idea-to-backlog.md", "expectation_ids": ["shaped-problem", "shaped-outcome", "shaped-constraints", "shaped-non-goals", "shaped-success", "shaped-risk", "open-decisions"] }, { "artifact": "trust.bundle#builder.shape", "expectation_ids": ["shaped-problem", "shaped-outcome", "shaped-constraints", "shaped-non-goals", "shaped-success", "shaped-risk", "open-decisions"] }]
115
177
  },
116
178
  {
117
179
  "flow_id": "builder.shape",
118
180
  "step_id": "breakdown",
119
181
  "skills": ["idea-to-backlog"],
120
- "expectation_ids": ["slices-defined"]
182
+ "implementation_allowed": false,
183
+ "artifacts": ["<slug>--idea-to-backlog.md", "trust.bundle#builder.shape"],
184
+ "expectation_ids": ["slices-defined"],
185
+ "expectation_bindings": [{ "expectation_id": "slices-defined", "interface": "workflow.evidence" }],
186
+ "artifact_bindings": [{ "artifact": "<slug>--idea-to-backlog.md", "expectation_ids": ["slices-defined"] }, { "artifact": "trust.bundle#builder.shape", "expectation_ids": ["slices-defined"] }]
121
187
  },
122
188
  {
123
189
  "flow_id": "builder.shape",
124
190
  "step_id": "file-issues",
125
191
  "skills": ["idea-to-backlog"],
126
- "expectation_ids": ["work-items-filed"]
192
+ "implementation_allowed": false,
193
+ "artifacts": ["<slug>--idea-to-backlog.md", "trust.bundle#builder.shape"],
194
+ "expectation_ids": ["work-items-filed"],
195
+ "expectation_bindings": [{ "expectation_id": "work-items-filed", "interface": "workflow.evidence" }],
196
+ "artifact_bindings": [{ "artifact": "<slug>--idea-to-backlog.md", "expectation_ids": ["work-items-filed"] }, { "artifact": "trust.bundle#builder.shape", "expectation_ids": ["work-items-filed"] }]
127
197
  },
128
198
  {
129
199
  "flow_id": "builder.shape",
130
200
  "step_id": "shape-done",
131
201
  "skills": [],
132
- "expectation_ids": []
202
+ "implementation_allowed": false,
203
+ "artifacts": [],
204
+ "expectation_ids": [],
205
+ "expectation_bindings": [],
206
+ "artifact_bindings": []
133
207
  }
134
208
  ],
135
209
  "hook_influence_expectations": [
@@ -90,9 +90,10 @@ Critique derives reviewer identity from the calling runtime actor. An active
90
90
  implementation assignment is required, and its actor cannot review its own
91
91
  work; the delegated reviewer invokes the command directly under a distinct
92
92
  identity. The public interface does not accept a caller-selected reviewer
93
- label. Every critique includes an explicit verdict, at least one substantive
94
- `--lane-json`, and local reviewed `--artifact-ref` values. Passing critiques
95
- require every lane to pass; reviewed files and the workspace snapshot are
93
+ label. Every critique includes an explicit `pass`, `fail`, or `not_verified`
94
+ verdict and at least one substantive `--lane-json`. Passing critiques additionally
95
+ require local reviewed `--artifact-ref` values and every lane to pass; reviewed
96
+ files and the workspace snapshot are
96
97
  hashed into the stored review target so later implementation changes invalidate
97
98
  stale clean critiques.
98
99
 
@@ -173,7 +174,13 @@ flow_agents workflow drive \
173
174
  Driver state and its append-only event stream live under
174
175
  `.kontourai/flow-agents/<slug>/continuation-driver/`. The mission turn count survives reinvocation;
175
176
  subsequent invocations must use the same `--max-turns` value. The request contains the
176
- canonical run id, definition id, current step, projected `next_action`, iteration, and budget. It
177
+ canonical run id, definition id, current step, projected `next_action`, iteration, and budget. Builder
178
+ turns additionally carry one bounded top-level `gate_action_envelope` with immutable skill identities,
179
+ declared artifacts/evidence, requirement satisfaction and unresolved ids, typed public
180
+ `workflow.evidence`/`workflow.critique` argv or product-operation bindings, one-turn stop semantics,
181
+ product-declared implementation policy, and prior canonical progress/stagnation. Parameter values are
182
+ appended as separate argv entries; adapters must not perform string substitution into a shell command. The
183
+ envelope is request-only and is not duplicated in projected `next_action` or durable `state.json`. It
177
184
  does not mutate or replace the runtime system prompt. Adapter errors are recorded as failed turns
178
185
  and fail open to canonical resynchronization and the next bounded turn; they cannot bypass the
179
186
  persisted mission budget. The Builder Flow projection supplies the canonical continue/wait/done/failed
@@ -188,6 +195,15 @@ state rollback or deletion is rejected when its append-only event history proves
188
195
  started. These local coordination records detect accidental or in-process rollback; they are not a
189
196
  cryptographic boundary against a process that can rewrite the entire artifact directory.
190
197
 
198
+ An operation mutation is a structured product protocol, not necessarily a directly executable CLI
199
+ command. In particular, `publish-change` identifies the provider capability `pull_request.create`,
200
+ its bounded parameters, the required provider result, and `publish-change.result.json` as its dedicated
201
+ result artifact. This release has no authenticated ChangeProvider executor. The operation therefore
202
+ reports `external_capability_required` and `external_verification_required`, exposes no completion
203
+ mutation, and parks the continuation. A locally authored result is not provider evidence. The installed
204
+ `flow-agents publish-change` helper renders and validates publish artifacts and provider checks; it does
205
+ not create a pull request and must not be treated as the operation executor.
206
+
191
207
  Immediately before spawning an adapter turn, the driver writes a transient, schema-versioned
192
208
  `active-turn.json` beside its mission state and passes a raw 32-byte turn secret plus the path-safe,
193
209
  signed run id in `FLOW_AGENTS_CONTINUATION_TURN_SECRET` and
@@ -230,7 +246,27 @@ The event stream records `turn_completed`, `gate_not_advanced`, `turn_failed`, a
230
246
  outcome. Failed turns carry
231
247
  `failure_kind` of `timeout` or `adapter_error`; a completed adapter turn whose canonical run remains
232
248
  active at the same current step records `gate_not_advanced`. These events describe driver execution only and do not
233
- change canonical Flow state.
249
+ change canonical Flow state. Adapter-returned `evidence` is not interpreted as gate evidence; only
250
+ the public `workflow evidence` path can attach evidence for Flow evaluation. Same-step canonical
251
+ evidence or declared-artifact hash changes are recorded as progress, while repeated no-progress turns are
252
+ classified as possible stagnation and then stagnant without fabricating a gate outcome.
253
+ Progress uses run-wide canonical evidence/artifact manifests and resumes
254
+ from the durable `last_progress` baseline after interruption or reinvocation. Kit metadata, skill source,
255
+ and observed artifact reads are bounded descriptor-stable regular-file reads that reject symlinks and
256
+ identity changes.
257
+ Request-facing declared and required artifacts exclude control `state.json`, even where legacy kit
258
+ ownership metadata retains it.
259
+ Kit validation and envelope construction both cap an action at 16 skills and a flow at 128 distinct
260
+ observable file artifacts, excluding virtual trust-bundle refs and control artifacts consistently.
261
+ Synchronization measures an interrupted, waiting, terminal, or callback-failed turn before clearing
262
+ its recovery marker. Evidence-free canonical gate evaluation is limited to accepted exceptions and
263
+ gates whose effective expectations are all optional; ordinary missing-required gates remain unevaluated.
264
+ Signed drives reserve aggregate attestation capacity before adapter execution when another bounded
265
+ signed result cannot fit.
266
+ The complete serialized adapter result is capped at 74,000 bytes, and preflight reserves that exact
267
+ maximum plus the actual request and JSON structure. Accepted request/result pairs and measured progress
268
+ are journaled durably before the active marker is cleared. Restart idempotently completes missing audit
269
+ writes, and signed attestation fails closed when persisted accepted events lack journal coverage.
234
270
 
235
271
  ## Compatibility Doctor
236
272
 
@@ -153,6 +153,123 @@ composed steps that have no legacy sidecar phase (`merge-ready-ci` and `learn`).
153
153
  Both the legacy `current.json` pointer and every matching per-actor pointer are
154
154
  updated from that canonical step; `phase_map` is presentation metadata, not the
155
155
  authority for pointer navigation.
156
+
157
+ ### Gate-Action Envelope
158
+
159
+ Every active Builder continuation request includes a bounded
160
+ `gate_action_envelope` with schema version `1.0`. Flow Agents derives it from
161
+ the persisted canonical Flow run and effective Flow Definition, then joins it
162
+ to the installed Builder Kit's validated `flow_step_actions` record. It is an
163
+ execution context, not a second gate evaluator: Flow remains the only authority
164
+ that evaluates requirements, advances steps, routes back, or consumes attempt
165
+ budget.
166
+
167
+ The envelope provides the current gate ids and claim shapes, including each
168
+ expectation's required flag and `satisfied`, `accepted_exception`, or `unresolved`
169
+ status. Accepted exceptions are identified separately. Flow Agents evaluates
170
+ these statuses with the run's effective Flow config, including gate overrides,
171
+ so waived, satisfied, and optional work is never mislabeled as required. Skill
172
+ identities bind package, version, stable package-relative source
173
+ path, and SHA-256, so durable attestations never retain a stale absolute install path.
174
+ Requirement status comes from Flow's canonical gate evaluation and therefore
175
+ uses the expectation's trust-bundle selector, Surface-derived claim status,
176
+ supersession, freshness, and current gate visit; `expectation_ids` labels alone
177
+ never mark a requirement satisfied.
178
+ Declared operations, artifacts, and evidence expectation ids come from product
179
+ metadata. `implementation_allowed` is also product metadata; the shipped Builder
180
+ Kit declares it true only for `builder.build/execute`.
181
+
182
+ The read-only status interface is an exact version-pinned command. Mutation
183
+ interfaces are typed per expectation: `workflow.evidence`, `workflow.critique`,
184
+ or a named product operation such as `publish-change`. Evidence and critique
185
+ interfaces expose fixed argv plus typed required parameters and allowed values;
186
+ they do not publish shell strings with substitution placeholders. Consumers add
187
+ parameter values as distinct argv entries.
188
+
189
+ `publish-change` is a provider-capability protocol, not a claim that the local
190
+ `flow-agents publish-change` helper opens a pull request. Its envelope binds the
191
+ exact `pull_request.create` capability, bounded structured inputs, the required
192
+ provider result, and the dedicated session-relative
193
+ `publish-change.result.json` artifact. No authenticated ChangeProvider executor
194
+ ships in this issue, so the operation is explicitly unavailable locally and has
195
+ an `external_verification_required` completion state. It exposes no
196
+ `record_completion` mutation, a self-authored result cannot satisfy
197
+ `pull-request-opened`, and the projection waits instead of scheduling repeated
198
+ adapter turns. The protocol remains the future provider contract. The local
199
+ publish-change helper only renders and validates publish artifacts and provider
200
+ checks; it is not the provider action executor.
201
+
202
+ `flow_step_actions` must explicitly declare `artifacts`, `artifact_bindings`,
203
+ `expectation_ids`, `expectation_bindings`, and `implementation_allowed`, including
204
+ empty lists for terminal actions. Expectation ids must exactly equal the resolved
205
+ Flow expectation set. Artifact bindings map each artifact to its owning
206
+ expectations, allowing optional artifacts to remain declared without appearing
207
+ under `stop_condition.required`. Operation bindings must resolve through the
208
+ canonical public operation catalog, not merely a self-declared string. Artifact
209
+ refs are either lexically safe session-relative paths or validated
210
+ `trust.bundle#<safe-id>` virtual refs; absolute paths, traversal, and arbitrary
211
+ fragments fail closed. Malformed,
212
+ unknown-field, duplicate, oversized, unmatched, symlinked, or otherwise
213
+ unbounded action metadata fails closed before an adapter is launched. The
214
+ runtime verifies every named skill against the installed Builder package and
215
+ binds its contents by SHA-256. Kit JSON, skill source, and artifact identity/hash
216
+ reads open the final path once with `O_NOFOLLOW`, bound size from `fstat`, read
217
+ through that descriptor, and recheck descriptor/path identity after the read.
218
+ Run-wide artifact observation deduplicates refs and enforces count plus aggregate
219
+ byte/hash budgets before reading file contents. Product validation and runtime
220
+ both cap each action at 16 skills and each flow at 128 distinct observable file
221
+ artifacts; virtual trust-bundle refs and control artifacts are excluded using the
222
+ same classification in both layers.
223
+
224
+ After every successful or failed adapter turn, Flow Agents synchronizes the
225
+ canonical run and records a delta: step advancement, newly attached canonical
226
+ evidence, changed hashes of declared artifacts (`artifact_changes`), or no
227
+ progress. Evidence identities and the artifact manifest are run-wide rather
228
+ than selected-step scoped, so the evidence/artifact that advances a gate remains
229
+ attributable and files already present for later steps are part of the baseline.
230
+ Control `state.json` is excluded from both request-facing declared/required
231
+ artifacts and artifact progress. Legacy kit ownership metadata may retain it,
232
+ but the envelope never instructs an adapter to produce Flow Agents control
233
+ state or observes its own hash. Repeated
234
+ no-progress deltas are classified as `possible` and then `stagnant`; they never
235
+ invent evidence, auto-pass a gate, or change Flow state. A same-step evidence
236
+ attachment is recorded as progress even though the legacy `gate_not_advanced`
237
+ event remains for compatibility. Adapter-returned `evidence` remains optional
238
+ adapter telemetry only and is never gate evidence.
239
+
240
+ The durable `last_progress` snapshot is the recovery baseline. A durable active
241
+ turn phase and pre-turn snapshot identify an adapter turn interrupted before its
242
+ post-turn measurement. Reinvocation compares freshly synchronized canonical
243
+ state with that snapshot, counts an unchanged started turn as no progress exactly
244
+ once, records any delta, and clears the recovery marker. Synchronization and this
245
+ reconciliation occur before waiting or terminal disposition handling, so the
246
+ turn's audit and progress survive either outcome. Accepted turns, wait turns, and
247
+ callback failures are likewise synchronized and measured before their durable
248
+ turn marker is cleared. Signed workflow drives preflight the aggregate attestation
249
+ capacity before launching an adapter when another bounded signed result cannot fit.
250
+ Accepted request/result pairs and their measured progress are first stored in a
251
+ durable idempotent journal while the active turn remains in `measured` phase.
252
+ Only after journal and completion-event persistence does the driver clear that
253
+ marker. Restart completes either write exactly once. Signed attestations reload
254
+ the journal and fail closed if an accepted event lacks request/result coverage.
255
+ The complete serialized turn result is capped at 74,000 bytes; signed preflight
256
+ reserves that exact maximum in addition to the actual request and JSON structure.
257
+ The authoritative envelope
258
+ exists only at top-level in the turn request; projected `next_action` and durable
259
+ `state.json` do not contain a duplicate.
260
+
261
+ Canonical synchronization normally waits for attached bundle evidence before
262
+ evaluating a gate. It may evaluate an evidence-free gate only when the run's
263
+ effective config proves the gate can pass without new evidence: an accepted
264
+ exception applies, or every effective expectation is optional. This advances
265
+ those gates without prematurely evaluating ordinary missing-required gates, and
266
+ once the run advances no obsolete action skill remains required.
267
+
268
+ The envelope and its prior-turn delta are additive fields of
269
+ `ContinuationTurnRequest` schema `1.0`; adapters that only consume the existing
270
+ request fields remain compatible. When `workflow drive` produces its optional
271
+ signed request/result attestation, the exact request object (including the
272
+ envelope) is included in the signed payload without transformation.
156
273
  # Builder Lifecycle Authority
157
274
 
158
275
  The canonical Flow run owns pause, resume, and cancellation. The current assignment actor may