@kontourai/flow-agents 2.3.0 → 3.0.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 (301) hide show
  1. package/.github/CODEOWNERS +16 -0
  2. package/.github/workflows/ci.yml +44 -0
  3. package/.github/workflows/trust-reconcile.yml +62 -4
  4. package/AGENTS.md +4 -4
  5. package/CHANGELOG.md +62 -0
  6. package/CONTEXT.md +35 -0
  7. package/README.md +9 -3
  8. package/agents/dev.json +1 -1
  9. package/agents/tool-code-reviewer.json +1 -1
  10. package/agents/tool-planner.json +3 -3
  11. package/agents/tool-verifier.json +3 -3
  12. package/build/src/cli/assignment-provider.d.ts +1 -0
  13. package/build/src/cli/assignment-provider.js +748 -0
  14. package/build/src/cli/console-learning-projection.js +3 -2
  15. package/build/src/cli/effective-assignment-provider-settings.d.ts +1 -0
  16. package/build/src/cli/effective-assignment-provider-settings.js +125 -0
  17. package/build/src/cli/init.js +104 -21
  18. package/build/src/cli/kit.js +37 -6
  19. package/build/src/cli/pull-work-provider.js +1 -1
  20. package/build/src/cli/usage-feedback.js +3 -3
  21. package/build/src/cli/validate-hook-influence.js +1 -0
  22. package/build/src/cli/validate-workflow-artifacts.js +27 -7
  23. package/build/src/cli/workflow-artifact-cleanup-audit.js +36 -2
  24. package/build/src/cli/workflow-sidecar.d.ts +14 -7
  25. package/build/src/cli/workflow-sidecar.js +938 -168
  26. package/build/src/cli.js +6 -0
  27. package/build/src/flow-kit/validate.d.ts +23 -0
  28. package/build/src/flow-kit/validate.js +67 -1
  29. package/build/src/index.d.ts +1 -1
  30. package/build/src/index.js +1 -1
  31. package/build/src/lib/flow-resolver.d.ts +6 -4
  32. package/build/src/lib/flow-resolver.js +125 -58
  33. package/build/src/lib/local-artifact-root.d.ts +14 -2
  34. package/build/src/lib/local-artifact-root.js +22 -5
  35. package/build/src/lib/workflow-learning-projection.js +2 -2
  36. package/build/src/runtime-adapters.d.ts +12 -0
  37. package/build/src/runtime-adapters.js +56 -16
  38. package/build/src/tools/build-universal-bundles.js +49 -16
  39. package/build/src/tools/generate-context-map.js +10 -8
  40. package/build/src/tools/validate-source-tree.js +24 -1
  41. package/console.telemetry.json +22 -0
  42. package/context/contracts/artifact-contract.md +40 -7
  43. package/context/contracts/assignment-provider-contract.md +239 -0
  44. package/context/contracts/builder-kit-workflow-state-contract.md +5 -2
  45. package/context/contracts/decision-registry-contract.md +265 -0
  46. package/context/contracts/delivery-contract.md +3 -1
  47. package/context/contracts/execution-contract.md +25 -0
  48. package/context/contracts/governance-adapter-contract.md +2 -0
  49. package/context/contracts/knowledge-store-contract.md +197 -0
  50. package/context/contracts/planning-contract.md +4 -1
  51. package/context/contracts/review-contract.md +7 -3
  52. package/context/contracts/sandbox-policy.md +2 -0
  53. package/context/contracts/standing-directives.md +13 -0
  54. package/context/contracts/verification-contract.md +11 -1
  55. package/context/contracts/work-item-contract.md +3 -1
  56. package/context/deferred/parallelization.md +1 -1
  57. package/context/gate-awareness.md +4 -4
  58. package/context/scripts/git-status.sh +2 -2
  59. package/context/scripts/hooks/config-protection.js +502 -2
  60. package/context/scripts/hooks/lib/config-protection-remedies.js +69 -0
  61. package/context/scripts/hooks/run-hook.js +14 -1
  62. package/context/scripts/hooks/stop-goal-fit.js +1140 -99
  63. package/context/scripts/hooks/workflow-steering.js +212 -6
  64. package/context/settings/assignment-provider-settings.json +33 -0
  65. package/docs/adr/0007-flow-skill-kit-tool-boundary.md +2 -0
  66. package/docs/adr/0015-flow-flow-agents-boundary-reconciliation.md +35 -0
  67. package/docs/adr/0019-kit-dependency-ownership.md +62 -0
  68. package/docs/adr/0020-trust-reconcile-manifest-and-claim-classification.md +290 -0
  69. package/docs/adr/0021-assignment-leases-and-stale-claim-takeover.md +221 -0
  70. package/docs/adr/0022-fail-closed-delivery-reconciliation-with-governed-exemptions.md +463 -0
  71. package/docs/agent-system-guidebook.md +3 -3
  72. package/docs/agent-usage-feedback-loop.md +6 -6
  73. package/docs/context-map.md +10 -7
  74. package/docs/decisions/decision-records.md +57 -0
  75. package/docs/decisions/index.md +17 -0
  76. package/docs/decisions/knowledge-store-provider.md +51 -0
  77. package/docs/decisions/model-routing.md +63 -0
  78. package/docs/decisions/promotion-gate.md +52 -0
  79. package/docs/decisions/standing-directives.md +66 -0
  80. package/docs/developer-architecture.md +1 -1
  81. package/docs/fixture-ownership.md +4 -0
  82. package/docs/flow-kit-repository-contract.md +5 -5
  83. package/docs/getting-started.md +12 -2
  84. package/docs/integrations/harness-install.md +2 -1
  85. package/docs/kit-authoring-guide.md +64 -5
  86. package/docs/knowledge-kit.md +5 -1
  87. package/docs/learnings/2026-07-improvement-program.md +203 -0
  88. package/docs/migrations.md +6 -5
  89. package/docs/north-star.md +2 -2
  90. package/docs/operating-layers.md +4 -3
  91. package/docs/repository-structure.md +5 -5
  92. package/docs/skills-map.md +8 -8
  93. package/docs/spec/runtime-hook-surface.md +19 -15
  94. package/docs/spikes/graph-provider-2026-07.md +155 -0
  95. package/docs/standards-register.md +7 -7
  96. package/docs/trust-anchor-adoption.md +105 -4
  97. package/docs/work-item-adapters.md +1 -1
  98. package/docs/workflow-artifact-lifecycle.md +72 -9
  99. package/docs/workflow-eval-strategy.md +3 -3
  100. package/docs/workflow-shared-contracts.md +3 -2
  101. package/docs/workflow-usage-guide.md +260 -21
  102. package/evals/acceptance/DEMO-false-completion.md +20 -11
  103. package/evals/acceptance/prove-capture-teeth-declared.sh +15 -15
  104. package/evals/acceptance/prove-capture-teeth.sh +11 -11
  105. package/evals/acceptance/test_kiro_harness.sh +1 -1
  106. package/evals/ci/antigaming-suite.sh +5 -0
  107. package/evals/ci/run-baseline.sh +71 -1
  108. package/evals/fixtures/assignment-provider/actor-a.json +6 -0
  109. package/evals/fixtures/assignment-provider/actor-b.json +6 -0
  110. package/evals/fixtures/assignment-provider/github-issue-claimed.json +27 -0
  111. package/evals/fixtures/assignment-provider/github-issue-unassigned.json +7 -0
  112. package/evals/fixtures/assignment-provider/liveness-fresh.json +9 -0
  113. package/evals/fixtures/assignment-provider/liveness-stale.json +9 -0
  114. package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/flows/review.flow.json +26 -0
  115. package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/kit.json +13 -0
  116. package/evals/fixtures/flow-kit-repository/valid-with-dependency/flows/review.flow.json +26 -0
  117. package/evals/fixtures/flow-kit-repository/valid-with-dependency/kit.json +13 -0
  118. package/evals/fixtures/hook-influence/cases.json +32 -0
  119. package/evals/fixtures/pull-work-provider/github-issues.json +6 -6
  120. package/evals/fixtures/trust-reconcile-exploits/fabricated-attestation.json +59 -0
  121. package/evals/fixtures/trust-reconcile-exploits/no-label-bypass.json +36 -0
  122. package/evals/fixtures/trust-reconcile-exploits/skip-assumed-bypass.json +59 -0
  123. package/evals/fixtures/trust-reconcile-exploits/status-misassertion.json +48 -0
  124. package/evals/fixtures/trust-reconcile-exploits/waived-command-check.json +44 -0
  125. package/evals/fixtures/trust-reconcile-mixed-bundle/mixed-bundle.json +159 -0
  126. package/evals/fixtures/trust-reconcile-ws3/ws3-bundle.json +920 -0
  127. package/evals/integration/test_actor_identity.sh +254 -0
  128. package/evals/integration/test_assignment_provider_github.sh +318 -0
  129. package/evals/integration/test_assignment_provider_local_file.sh +222 -0
  130. package/evals/integration/test_builder_step_producers.sh +33 -23
  131. package/evals/integration/test_bundle_install.sh +22 -16
  132. package/evals/integration/test_bundle_lifecycle.sh +11 -11
  133. package/evals/integration/test_captured_fail_reconciliation.sh +50 -50
  134. package/evals/integration/test_checkpoint_signing.sh +43 -0
  135. package/evals/integration/test_claim_lookup.sh +4 -4
  136. package/evals/integration/test_codex_hook_resolution.sh +114 -0
  137. package/evals/integration/test_command_log_concurrency.sh +8 -8
  138. package/evals/integration/test_command_log_fork_classification.sh +3 -3
  139. package/evals/integration/test_command_log_integrity.sh +16 -16
  140. package/evals/integration/test_console_learning_projection.sh +1 -1
  141. package/evals/integration/test_critique_supersession_roundtrip.sh +182 -0
  142. package/evals/integration/test_dual_emit_flow_step.sh +145 -0
  143. package/evals/integration/test_enforcer_expects_driven.sh +12 -12
  144. package/evals/integration/test_evidence_capture_hook.sh +14 -13
  145. package/evals/integration/test_fixture_retirement_audit.sh +2 -2
  146. package/evals/integration/test_flow_agents_statusline.sh +2 -2
  147. package/evals/integration/test_flow_kit_install_git.sh +52 -0
  148. package/evals/integration/test_flow_kit_repository.sh +2 -0
  149. package/evals/integration/test_flowdef_session_activation.sh +6 -6
  150. package/evals/integration/test_flowdef_union_floor_regression.sh +429 -0
  151. package/evals/integration/test_gate_bypass_chain.sh +52 -40
  152. package/evals/integration/test_gate_lockdown.sh +97 -73
  153. package/evals/integration/test_gate_review_inquiry_records.sh +3 -3
  154. package/evals/integration/test_goal_fit_escape_hatch.sh +10 -10
  155. package/evals/integration/test_goal_fit_ghost_session.sh +104 -0
  156. package/evals/integration/test_goal_fit_hook.sh +32 -32
  157. package/evals/integration/test_goal_fit_rederive.sh +9 -9
  158. package/evals/integration/test_hook_category_behaviors.sh +103 -0
  159. package/evals/integration/test_hook_influence_cases.sh +1 -0
  160. package/evals/integration/test_install_merge.sh +262 -1
  161. package/evals/integration/test_kit_identity_trust.sh +6 -6
  162. package/evals/integration/test_liveness_conflict_injection.sh +587 -0
  163. package/evals/integration/test_liveness_heartbeat.sh +677 -0
  164. package/evals/integration/test_liveness_verdict.sh +394 -0
  165. package/evals/integration/test_local_flow_kit_install.sh +15 -0
  166. package/evals/integration/test_phase_map_and_gate_claim.sh +63 -11
  167. package/evals/integration/test_promote_gate.sh +178 -0
  168. package/evals/integration/test_publish_delivery.sh +23 -6
  169. package/evals/integration/test_pull_work_assignment_join.sh +132 -0
  170. package/evals/integration/test_pull_work_liveness_preflight.sh +394 -0
  171. package/evals/integration/test_pull_work_provider.sh +2 -2
  172. package/evals/integration/test_reconcile_soundness.sh +37 -13
  173. package/evals/integration/test_resolvefirststep_security.sh +22 -0
  174. package/evals/integration/test_runtime_adapter_activation.sh +87 -18
  175. package/evals/integration/test_session_resume_roundtrip.sh +147 -0
  176. package/evals/integration/test_sidecar_field_preservation.sh +249 -0
  177. package/evals/integration/test_trust_reconcile.sh +11 -10
  178. package/evals/integration/test_trust_reconcile_manifest.sh +79 -0
  179. package/evals/integration/test_trust_reconcile_mixed_bundle.sh +96 -0
  180. package/evals/integration/test_trust_reconcile_negatives.sh +759 -0
  181. package/evals/integration/test_usage_feedback_global.sh +5 -5
  182. package/evals/integration/test_validate_artifacts_portability.sh +60 -0
  183. package/evals/integration/test_verify_cli.sh +2 -2
  184. package/evals/integration/test_veritas_governance_kit.sh +117 -0
  185. package/evals/integration/test_workflow_artifact_cleanup_audit.sh +26 -1
  186. package/evals/integration/test_workflow_artifacts.sh +33 -0
  187. package/evals/integration/test_workflow_sidecar_writer.sh +802 -74
  188. package/evals/integration/test_workflow_steering_hook.sh +175 -5
  189. package/evals/lib/codex-provider.sh +1 -1
  190. package/evals/lib/node.sh +19 -1
  191. package/evals/run.sh +32 -0
  192. package/evals/static/test_decisions.sh +150 -0
  193. package/evals/static/test_flowdef_codeowners_coverage.sh +62 -0
  194. package/evals/static/test_knowledge_providers.sh +23 -0
  195. package/evals/static/test_package.sh +19 -10
  196. package/evals/static/test_universal_bundles.sh +48 -3
  197. package/evals/static/test_workflow_skills.sh +41 -8
  198. package/kits/builder/flows/build.flow.json +3 -74
  199. package/kits/builder/flows/publish-learn.flow.json +90 -0
  200. package/kits/builder/kit.json +11 -0
  201. package/kits/builder/skills/builder-shape/SKILL.md +1 -1
  202. package/kits/builder/skills/deliver/SKILL.md +32 -11
  203. package/kits/builder/skills/design-probe/SKILL.md +4 -4
  204. package/kits/builder/skills/evidence-gate/SKILL.md +26 -1
  205. package/kits/builder/skills/execute-plan/SKILL.md +2 -2
  206. package/kits/builder/skills/fix-bug/SKILL.md +2 -0
  207. package/kits/builder/skills/gate-review/SKILL.md +6 -6
  208. package/kits/builder/skills/idea-to-backlog/SKILL.md +1 -1
  209. package/kits/builder/skills/learning-review/SKILL.md +7 -7
  210. package/kits/builder/skills/pickup-probe/SKILL.md +5 -4
  211. package/kits/builder/skills/plan-work/SKILL.md +27 -5
  212. package/kits/builder/skills/pull-work/SKILL.md +148 -5
  213. package/kits/builder/skills/release-readiness/SKILL.md +4 -4
  214. package/kits/builder/skills/review-work/SKILL.md +24 -1
  215. package/kits/builder/skills/tdd-workflow/SKILL.md +2 -0
  216. package/kits/builder/skills/verify-work/SKILL.md +8 -1
  217. package/kits/catalog.json +6 -0
  218. package/kits/knowledge/kit.json +35 -0
  219. package/kits/knowledge/providers/conformance/fixtures/git-repo/CONTEXT.md +12 -0
  220. package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/decisions/old-sprocket-shape.md +13 -0
  221. package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/decisions/sprocket-shape.md +14 -0
  222. package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/decisions/widget-format.md +14 -0
  223. package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/learnings/fixture-learning.md +7 -0
  224. package/kits/knowledge/providers/conformance/fixtures/work-item/issues.json +30 -0
  225. package/kits/knowledge/providers/conformance/suite.test.js +125 -0
  226. package/kits/knowledge/providers/git-repo/index.js +236 -0
  227. package/kits/knowledge/providers/health/health-pass.test.js +99 -0
  228. package/kits/knowledge/providers/health/index.js +153 -0
  229. package/kits/knowledge/providers/index.js +24 -0
  230. package/kits/knowledge/providers/lib/model.js +91 -0
  231. package/kits/knowledge/providers/lib/schema-validate.js +119 -0
  232. package/kits/knowledge/providers/markdown-vault/index.js +169 -0
  233. package/kits/knowledge/providers/work-item/index.js +204 -0
  234. package/kits/veritas-governance/adapter/readiness-to-trust-bundle.mjs +178 -0
  235. package/kits/veritas-governance/docs/README.md +75 -0
  236. package/kits/veritas-governance/fixtures/readiness/not-ready.readiness-report.json +4645 -0
  237. package/kits/veritas-governance/fixtures/readiness/ready.readiness-report.json +4403 -0
  238. package/kits/veritas-governance/flows/readiness-check.flow.json +35 -0
  239. package/kits/veritas-governance/kit.json +16 -0
  240. package/package.json +11 -5
  241. package/packaging/README.md +2 -2
  242. package/packaging/conformance/fixtures/config-protection--allow-read-state-json.json +20 -0
  243. package/packaging/conformance/fixtures/config-protection--block-write-state-json.json +20 -0
  244. package/packaging/conformance/fixtures/stop-goal-fit--block-bundle-disputed-claim.json +1 -1
  245. package/packaging/conformance/fixtures/stop-goal-fit--block-capture-contradicts-claimed-pass.json +1 -1
  246. package/packaging/manifest.json +9 -10
  247. package/schemas/assignment-provider-settings.schema.json +125 -0
  248. package/schemas/decision-record.schema.json +109 -0
  249. package/schemas/knowledge/edge.schema.json +54 -0
  250. package/schemas/knowledge/health-report.schema.json +45 -0
  251. package/schemas/knowledge/node.schema.json +49 -0
  252. package/schemas/knowledge/proposal.schema.json +53 -0
  253. package/schemas/workflow-evidence.schema.json +1 -1
  254. package/schemas/workflow-state.schema.json +5 -0
  255. package/scripts/README.md +8 -3
  256. package/scripts/check-content-boundary.cjs +1 -1
  257. package/scripts/check-decisions.cjs +356 -0
  258. package/scripts/ci/derive-claim-status.mjs +74 -0
  259. package/scripts/ci/trust-reconcile.js +957 -103
  260. package/scripts/git-status.sh +2 -2
  261. package/scripts/hooks/claude-telemetry-hook.js +37 -3
  262. package/scripts/hooks/codex-telemetry-hook.js +36 -2
  263. package/scripts/hooks/config-protection.js +102 -30
  264. package/scripts/hooks/evidence-capture.js +3 -3
  265. package/scripts/hooks/lib/actor-identity.js +368 -0
  266. package/scripts/hooks/lib/config-protection-remedies.js +69 -0
  267. package/scripts/hooks/lib/liveness-heartbeat.js +361 -0
  268. package/scripts/hooks/lib/liveness-policy.js +127 -0
  269. package/scripts/hooks/lib/liveness-read.js +105 -12
  270. package/scripts/hooks/lib/liveness-write.js +46 -0
  271. package/scripts/hooks/lib/local-artifact-paths.js +12 -6
  272. package/scripts/hooks/opencode-telemetry-hook.js +27 -1
  273. package/scripts/hooks/pi-telemetry-hook.js +27 -1
  274. package/scripts/hooks/stop-goal-fit.js +157 -26
  275. package/scripts/hooks/workflow-steering.js +77 -3
  276. package/scripts/install-codex-home.sh +138 -38
  277. package/scripts/statusline/flow-agents-statusline.js +2 -2
  278. package/src/cli/assignment-provider.ts +845 -0
  279. package/src/cli/console-learning-projection.ts +3 -2
  280. package/src/cli/effective-assignment-provider-settings.ts +112 -0
  281. package/src/cli/init.ts +101 -21
  282. package/src/cli/kit.ts +37 -6
  283. package/src/cli/public-api.test.mjs +58 -6
  284. package/src/cli/pull-work-provider.ts +1 -1
  285. package/src/cli/trust-bundle-policy-order.test.mjs +87 -0
  286. package/src/cli/usage-feedback.ts +3 -3
  287. package/src/cli/validate-hook-influence.ts +1 -0
  288. package/src/cli/validate-workflow-artifacts.ts +27 -7
  289. package/src/cli/veritas-readiness-adapter.test.mjs +267 -0
  290. package/src/cli/workflow-artifact-cleanup-audit.ts +35 -2
  291. package/src/cli/workflow-sidecar.ts +933 -168
  292. package/src/cli.ts +6 -0
  293. package/src/flow-kit/validate.ts +74 -1
  294. package/src/index.ts +6 -2
  295. package/src/lib/flow-resolver.ts +123 -55
  296. package/src/lib/local-artifact-root.ts +24 -5
  297. package/src/lib/workflow-learning-projection.ts +2 -2
  298. package/src/runtime-adapters.ts +61 -15
  299. package/src/tools/build-universal-bundles.ts +49 -16
  300. package/src/tools/generate-context-map.ts +10 -8
  301. package/src/tools/validate-source-tree.ts +24 -1
@@ -0,0 +1,222 @@
1
+ #!/usr/bin/env bash
2
+ # test_assignment_provider_local_file.sh — AssignmentProvider local-file round-trip (#290).
3
+ #
4
+ # Fully deterministic: exercises `assignment-provider claim|status|supersede|release|list
5
+ # --provider local-file` against a temp artifact root and two fixed test-actor fixtures. No
6
+ # network, no `gh` process, no live provider. Follows test_pull_work_provider.sh's
7
+ # pass/fail/json_query idiom exactly.
8
+ #
9
+ # Supports AC5 (local-file round-trip), AC6 (list --actor), AC7 (concurrent claim never
10
+ # silently overwrites), AC9 (no live gh process — none invoked here at all).
11
+ set -uo pipefail
12
+
13
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
14
+ CLI="$ROOT/build/src/cli.js"
15
+ FIXTURES="$ROOT/evals/fixtures/assignment-provider"
16
+ ACTOR_A="$FIXTURES/actor-a.json"
17
+ ACTOR_B="$FIXTURES/actor-b.json"
18
+ SUBJECT_ID="kontourai/flow-agents#9001"
19
+ BRANCH_A="agent/claude-code-eval-actor-a-session-eval-host/flow-agents-9001"
20
+ ARTIFACT_DIR_A=".kontourai/flow-agents/flow-agents-9001"
21
+
22
+ TMPDIR_EVAL="$(mktemp -d)"
23
+ trap 'rm -rf "$TMPDIR_EVAL"' EXIT
24
+ ARTIFACT_ROOT="$TMPDIR_EVAL/artifact-root"
25
+
26
+ errors=0
27
+ pass() { echo " ✓ $1"; }
28
+ fail() { echo " ✗ $1"; errors=$((errors + 1)); }
29
+
30
+ json_query() {
31
+ node -e 'const fs=require("fs"); let cur=JSON.parse(fs.readFileSync(process.argv[1],"utf8")); for (const part of process.argv[2].split(".")) cur=part==="length" ? cur.length : (Array.isArray(cur) ? cur[Number(part)] : cur[part]); console.log(cur);' "$1" "$2"
32
+ }
33
+
34
+ if [[ ! -f "$CLI" ]]; then
35
+ echo "build/src/cli.js not found — run 'npm run build' first" >&2
36
+ exit 1
37
+ fi
38
+
39
+ echo "=== AssignmentProvider: local-file round-trip ==="
40
+
41
+ # 1. claim writes the exact versioned record shape (Design Decision 2) for a fixed test actor.
42
+ node "$CLI" assignment-provider claim \
43
+ --provider local-file --artifact-root "$ARTIFACT_ROOT" \
44
+ --subject-id "$SUBJECT_ID" \
45
+ --actor-json "$ACTOR_A" \
46
+ --branch "$BRANCH_A" \
47
+ --artifact-dir "$ARTIFACT_DIR_A" \
48
+ --ttl-seconds 1800 \
49
+ > "$TMPDIR_EVAL/claim-a.json"
50
+ status=$?
51
+ [[ "$status" -eq 0 ]] && pass "claim exits successfully" || fail "claim exits successfully"
52
+
53
+ [[ "$(json_query "$TMPDIR_EVAL/claim-a.json" "record.schema_version")" == "1.0" ]] && pass "claim record schema_version is 1.0" || fail "claim record schema_version is 1.0"
54
+ [[ "$(json_query "$TMPDIR_EVAL/claim-a.json" "record.role")" == "AssignmentClaimRecord" ]] && pass "claim record role is AssignmentClaimRecord" || fail "claim record role is AssignmentClaimRecord"
55
+ [[ "$(json_query "$TMPDIR_EVAL/claim-a.json" "record.subject_id")" == "$SUBJECT_ID" ]] && pass "claim record subject_id matches" || fail "claim record subject_id matches"
56
+ [[ "$(json_query "$TMPDIR_EVAL/claim-a.json" "record.actor.session_id")" == "eval-actor-a-session" ]] && pass "claim record actor matches fixed test actor A" || fail "claim record actor matches fixed test actor A"
57
+ [[ "$(json_query "$TMPDIR_EVAL/claim-a.json" "record.ttl_seconds")" == "1800" ]] && pass "claim record ttl_seconds matches" || fail "claim record ttl_seconds matches"
58
+ [[ "$(json_query "$TMPDIR_EVAL/claim-a.json" "record.branch")" == "$BRANCH_A" ]] && pass "claim record branch matches" || fail "claim record branch matches"
59
+ [[ "$(json_query "$TMPDIR_EVAL/claim-a.json" "record.artifact_dir")" == "$ARTIFACT_DIR_A" ]] && pass "claim record artifact_dir matches" || fail "claim record artifact_dir matches"
60
+ [[ "$(json_query "$TMPDIR_EVAL/claim-a.json" "record.status")" == "claimed" ]] && pass "claim record status is claimed" || fail "claim record status is claimed"
61
+ [[ "$(json_query "$TMPDIR_EVAL/claim-a.json" "record.audit_trail.0.transition")" == "claim" ]] && pass "claim record audit_trail records the claim transition" || fail "claim record audit_trail records the claim transition"
62
+
63
+ CLAIMED_AT="$(json_query "$TMPDIR_EVAL/claim-a.json" "record.claimed_at")"
64
+
65
+ # 2. status returns actor/claimedAt matching what claim wrote.
66
+ node "$CLI" assignment-provider status \
67
+ --provider local-file --artifact-root "$ARTIFACT_ROOT" --subject-id "$SUBJECT_ID" \
68
+ > "$TMPDIR_EVAL/status-a.json"
69
+ [[ "$(json_query "$TMPDIR_EVAL/status-a.json" "assignment.assignee")" == "claude-code:eval-actor-a-session:eval-host" ]] && pass "status reports actor A as assignee" || fail "status reports actor A as assignee"
70
+ [[ "$(json_query "$TMPDIR_EVAL/status-a.json" "assignment.record.claimed_at")" == "$CLAIMED_AT" ]] && pass "status claimed_at matches claim's claimed_at" || fail "status claimed_at matches claim's claimed_at"
71
+
72
+ # 3. supersede A -> B updates the actor and records an audit trail entry.
73
+ node "$CLI" assignment-provider supersede \
74
+ --provider local-file --artifact-root "$ARTIFACT_ROOT" --subject-id "$SUBJECT_ID" \
75
+ --from-actor-json "$ACTOR_A" --to-actor-json "$ACTOR_B" --reason "handoff-eval" \
76
+ > "$TMPDIR_EVAL/supersede.json"
77
+ status=$?
78
+ [[ "$status" -eq 0 ]] && pass "supersede exits successfully" || fail "supersede exits successfully"
79
+ [[ "$(json_query "$TMPDIR_EVAL/supersede.json" "record.actor.session_id")" == "eval-actor-b-session" ]] && pass "supersede updates the record's actor to B" || fail "supersede updates the record's actor to B"
80
+ [[ "$(json_query "$TMPDIR_EVAL/supersede.json" "record.audit_trail.length")" == "2" ]] && pass "supersede appends to the audit trail (claim + supersede)" || fail "supersede appends to the audit trail (claim + supersede)"
81
+ [[ "$(json_query "$TMPDIR_EVAL/supersede.json" "record.audit_trail.1.transition")" == "supersede" ]] && pass "audit trail records the supersede transition" || fail "audit trail records the supersede transition"
82
+ [[ "$(json_query "$TMPDIR_EVAL/supersede.json" "record.audit_trail.1.from_actor.session_id")" == "eval-actor-a-session" ]] && pass "audit trail supersede entry records from_actor A" || fail "audit trail supersede entry records from_actor A"
83
+ [[ "$(json_query "$TMPDIR_EVAL/supersede.json" "record.audit_trail.1.to_actor.session_id")" == "eval-actor-b-session" ]] && pass "audit trail supersede entry records to_actor B" || fail "audit trail supersede entry records to_actor B"
84
+ [[ "$(json_query "$TMPDIR_EVAL/supersede.json" "record.audit_trail.1.reason")" == "handoff-eval" ]] && pass "audit trail supersede entry records reason" || fail "audit trail supersede entry records reason"
85
+
86
+ node "$CLI" assignment-provider status \
87
+ --provider local-file --artifact-root "$ARTIFACT_ROOT" --subject-id "$SUBJECT_ID" \
88
+ > "$TMPDIR_EVAL/status-b.json"
89
+ [[ "$(json_query "$TMPDIR_EVAL/status-b.json" "assignment.assignee")" == "claude-code:eval-actor-b-session:eval-host" ]] && pass "status reports actor B after supersede" || fail "status reports actor B after supersede"
90
+
91
+ # 4. release clears the claim; subsequent status reports free.
92
+ node "$CLI" assignment-provider release \
93
+ --provider local-file --artifact-root "$ARTIFACT_ROOT" --subject-id "$SUBJECT_ID" \
94
+ --actor-json "$ACTOR_B" \
95
+ > "$TMPDIR_EVAL/release.json"
96
+ status=$?
97
+ [[ "$status" -eq 0 ]] && pass "release exits successfully" || fail "release exits successfully"
98
+ [[ "$(json_query "$TMPDIR_EVAL/release.json" "record.status")" == "released" ]] && pass "release sets record status to released" || fail "release sets record status to released"
99
+
100
+ node "$CLI" assignment-provider status \
101
+ --provider local-file --artifact-root "$ARTIFACT_ROOT" --subject-id "$SUBJECT_ID" \
102
+ --liveness-events-json <(echo '[]') \
103
+ > "$TMPDIR_EVAL/status-free.json"
104
+ [[ "$(json_query "$TMPDIR_EVAL/status-free.json" "assignment.assignee")" == "null" ]] && pass "status reports no assignee after release" || fail "status reports no assignee after release"
105
+ [[ "$(json_query "$TMPDIR_EVAL/status-free.json" "effective.effective_state")" == "free" ]] && pass "status reports effective_state free after release" || fail "status reports effective_state free after release"
106
+
107
+ # 5. list --actor returns exactly that actor's claimed subject ids (claim a second subject
108
+ # under actor A, then verify list --actor A returns exactly that one subject).
109
+ SUBJECT_ID_2="kontourai/flow-agents#9002"
110
+ node "$CLI" assignment-provider claim \
111
+ --provider local-file --artifact-root "$ARTIFACT_ROOT" \
112
+ --subject-id "$SUBJECT_ID_2" \
113
+ --actor-json "$ACTOR_A" \
114
+ --branch "agent/claude-code-eval-actor-a-session-eval-host/flow-agents-9002" \
115
+ --artifact-dir ".kontourai/flow-agents/flow-agents-9002" \
116
+ > /dev/null
117
+ node "$CLI" assignment-provider list \
118
+ --provider local-file --artifact-root "$ARTIFACT_ROOT" --actor-json "$ACTOR_A" \
119
+ > "$TMPDIR_EVAL/list-a.json"
120
+ [[ "$(json_query "$TMPDIR_EVAL/list-a.json" "subject_ids.length")" == "1" ]] && pass "list --actor A returns exactly one subject id" || fail "list --actor A returns exactly one subject id"
121
+ [[ "$(json_query "$TMPDIR_EVAL/list-a.json" "subject_ids.0")" == "$SUBJECT_ID_2" ]] && pass "list --actor A returns actor A's currently-claimed subject (released subject excluded)" || fail "list --actor A returns actor A's currently-claimed subject (released subject excluded)"
122
+
123
+ node "$CLI" assignment-provider list \
124
+ --provider local-file --artifact-root "$ARTIFACT_ROOT" --actor-json "$ACTOR_B" \
125
+ > "$TMPDIR_EVAL/list-b.json"
126
+ [[ "$(json_query "$TMPDIR_EVAL/list-b.json" "subject_ids.length")" == "0" ]] && pass "list --actor B returns no subject ids (its only claim was released)" || fail "list --actor B returns no subject ids (its only claim was released)"
127
+
128
+ # 6. Two concurrent claims on the same subject from different actors: the second call must
129
+ # fail loud (non-zero exit + holder-identifying error), never silently overwrite the first
130
+ # (AC7; artifact-contract.md's "fail loud, never fail-open" persistence rule).
131
+ node "$CLI" assignment-provider claim \
132
+ --provider local-file --artifact-root "$ARTIFACT_ROOT" \
133
+ --subject-id "$SUBJECT_ID_2" \
134
+ --actor-json "$ACTOR_B" \
135
+ --branch "agent/claude-code-eval-actor-b-session-eval-host/flow-agents-9002" \
136
+ --artifact-dir ".kontourai/flow-agents/flow-agents-9002" \
137
+ > "$TMPDIR_EVAL/concurrent-claim.json" 2> "$TMPDIR_EVAL/concurrent-claim.err"
138
+ concurrent_status=$?
139
+ [[ "$concurrent_status" -ne 0 ]] && pass "second claim from a different actor fails loud (non-zero exit)" || fail "second claim from a different actor fails loud (non-zero exit)"
140
+ grep -q "already claimed by a different actor" "$TMPDIR_EVAL/concurrent-claim.err" && pass "second claim's error identifies the existing holder" || fail "second claim's error identifies the existing holder"
141
+
142
+ node "$CLI" assignment-provider status \
143
+ --provider local-file --artifact-root "$ARTIFACT_ROOT" --subject-id "$SUBJECT_ID_2" \
144
+ > "$TMPDIR_EVAL/status-after-concurrent.json"
145
+ [[ "$(json_query "$TMPDIR_EVAL/status-after-concurrent.json" "assignment.assignee")" == "claude-code:eval-actor-a-session:eval-host" ]] && pass "record still shows actor A as holder — no silent overwrite" || fail "record still shows actor A as holder — no silent overwrite"
146
+
147
+ # Same-actor re-claim (refresh before TTL expiry) is allowed and idempotent — must not error.
148
+ node "$CLI" assignment-provider claim \
149
+ --provider local-file --artifact-root "$ARTIFACT_ROOT" \
150
+ --subject-id "$SUBJECT_ID_2" \
151
+ --actor-json "$ACTOR_A" \
152
+ --branch "agent/claude-code-eval-actor-a-session-eval-host/flow-agents-9002" \
153
+ --artifact-dir ".kontourai/flow-agents/flow-agents-9002" \
154
+ > /dev/null 2>&1
155
+ [[ $? -eq 0 ]] && pass "same-actor re-claim (refresh) succeeds without error" || fail "same-actor re-claim (refresh) succeeds without error"
156
+
157
+ echo ""
158
+
159
+ # 7. F1 fix-plan iteration 1 (CRITICAL): GENUINE OS-process concurrency — two REAL,
160
+ # concurrently-launched `claim` processes (background `&` + `wait`, not the sequential case in
161
+ # section 6 above which never actually races) targeting the SAME fresh subject from DIFFERENT
162
+ # actors. Before the withSubjectLock fix, both processes could read "no existing claim" before
163
+ # either wrote, and one write would silently clobber the other (reproduced 29/40 races against
164
+ # the built CLI pre-fix). Assert EXACTLY ONE process exits 0, and the on-disk record shows
165
+ # exactly one holder with an intact, single-entry audit trail (no lost write).
166
+ SUBJECT_ID_RACE="kontourai/flow-agents#9003"
167
+ BRANCH_RACE_A="agent/claude-code-eval-actor-a-session-eval-host/flow-agents-9003"
168
+ BRANCH_RACE_B="agent/claude-code-eval-actor-b-session-eval-host/flow-agents-9003"
169
+ ARTIFACT_DIR_RACE=".kontourai/flow-agents/flow-agents-9003"
170
+
171
+ (
172
+ node "$CLI" assignment-provider claim \
173
+ --provider local-file --artifact-root "$ARTIFACT_ROOT" \
174
+ --subject-id "$SUBJECT_ID_RACE" \
175
+ --actor-json "$ACTOR_A" \
176
+ --branch "$BRANCH_RACE_A" \
177
+ --artifact-dir "$ARTIFACT_DIR_RACE" \
178
+ > "$TMPDIR_EVAL/race-a.out" 2> "$TMPDIR_EVAL/race-a.err"
179
+ echo $? > "$TMPDIR_EVAL/race-a.rc"
180
+ ) &
181
+ PID_A=$!
182
+ (
183
+ node "$CLI" assignment-provider claim \
184
+ --provider local-file --artifact-root "$ARTIFACT_ROOT" \
185
+ --subject-id "$SUBJECT_ID_RACE" \
186
+ --actor-json "$ACTOR_B" \
187
+ --branch "$BRANCH_RACE_B" \
188
+ --artifact-dir "$ARTIFACT_DIR_RACE" \
189
+ > "$TMPDIR_EVAL/race-b.out" 2> "$TMPDIR_EVAL/race-b.err"
190
+ echo $? > "$TMPDIR_EVAL/race-b.rc"
191
+ ) &
192
+ PID_B=$!
193
+ wait "$PID_A" "$PID_B"
194
+
195
+ RACE_RC_A="$(cat "$TMPDIR_EVAL/race-a.rc")"
196
+ RACE_RC_B="$(cat "$TMPDIR_EVAL/race-b.rc")"
197
+
198
+ if { [[ "$RACE_RC_A" -eq 0 && "$RACE_RC_B" -ne 0 ]] || [[ "$RACE_RC_A" -ne 0 && "$RACE_RC_B" -eq 0 ]]; }; then
199
+ pass "genuine concurrent claim race: exactly one process wins (rc_a=$RACE_RC_A rc_b=$RACE_RC_B)"
200
+ else
201
+ fail "genuine concurrent claim race: exactly one process wins (rc_a=$RACE_RC_A rc_b=$RACE_RC_B)"
202
+ fi
203
+
204
+ node "$CLI" assignment-provider status \
205
+ --provider local-file --artifact-root "$ARTIFACT_ROOT" --subject-id "$SUBJECT_ID_RACE" \
206
+ > "$TMPDIR_EVAL/status-race.json"
207
+ [[ "$(json_query "$TMPDIR_EVAL/status-race.json" "assignment.record.audit_trail.length")" == "1" ]] && pass "race winner's on-disk record has exactly one audit_trail entry (no lost/merged write)" || fail "race winner's on-disk record has exactly one audit_trail entry (no lost/merged write)"
208
+
209
+ if [[ "$RACE_RC_A" -eq 0 ]]; then
210
+ EXPECTED_RACE_HOLDER="claude-code:eval-actor-a-session:eval-host"
211
+ else
212
+ EXPECTED_RACE_HOLDER="claude-code:eval-actor-b-session:eval-host"
213
+ fi
214
+ [[ "$(json_query "$TMPDIR_EVAL/status-race.json" "assignment.assignee")" == "$EXPECTED_RACE_HOLDER" ]] && pass "on-disk record holder matches the process that actually exited 0 (no silent overwrite by the loser)" || fail "on-disk record holder matches the process that actually exited 0 (no silent overwrite by the loser)"
215
+
216
+ echo ""
217
+ if [[ "$errors" -eq 0 ]]; then
218
+ echo "test_assignment_provider_local_file: all checks passed."
219
+ else
220
+ echo "test_assignment_provider_local_file: $errors check(s) failed."
221
+ fi
222
+ exit "$errors"
@@ -15,8 +15,8 @@
15
15
  # 5. builder.learn.decisions (step: learn, expectation: decision-evidence)
16
16
  # 6. builder.learn.evidence (step: learn, expectation: learning-evidence)
17
17
  #
18
- # build.flow.json confirmation:
19
- # - All 6 claims above are required:true.
18
+ # Flow Definition confirmation:
19
+ # - All 6 claims above are required:true across builder.build and builder.publish-learn.
20
20
  # - policy-compliance remains required:false (advisory — no skill producer).
21
21
  #
22
22
  # Deterministic, no model spend, self-cleaning.
@@ -106,21 +106,21 @@ setup_tamper_session() {
106
106
  local t_dir="$1" slug="$2" step="$3"
107
107
  mkdir -p "$t_dir"
108
108
  printf '# Repo\n' > "$t_dir/AGENTS.md"
109
- mkdir -p "$t_dir/.flow-agents/$slug"
109
+ mkdir -p "$t_dir/.kontourai/flow-agents/$slug"
110
110
 
111
111
  flow_agents_node "workflow-sidecar" ensure-session \
112
- --artifact-root "$t_dir/.flow-agents" \
112
+ --artifact-root "$t_dir/.kontourai/flow-agents" \
113
113
  --task-slug "$slug" \
114
114
  --title "Tamper test: $step" \
115
115
  --summary "Testing tamper detection." \
116
116
  --flow-id builder.build \
117
117
  --timestamp "2026-06-26T00:00:00Z" >/dev/null 2>&1
118
118
 
119
- flow_agents_node "workflow-sidecar" init-plan "$t_dir/.flow-agents/$slug/$slug--deliver.md" \
119
+ flow_agents_node "workflow-sidecar" init-plan "$t_dir/.kontourai/flow-agents/$slug/$slug--deliver.md" \
120
120
  --source-request "Test" --summary "Testing" \
121
121
  --timestamp "2026-06-26T00:00:00Z" >/dev/null 2>&1
122
122
 
123
- set_active_step "$t_dir/.flow-agents" "$slug" "$step"
123
+ set_active_step "$t_dir/.kontourai/flow-agents" "$slug" "$step"
124
124
  }
125
125
 
126
126
  # ─── Test: produce a gate claim at a given step ───────────────────────────────
@@ -178,12 +178,12 @@ test_tamper_blocks() {
178
178
  setup_tamper_session "$t_dir" "$slug" "$step"
179
179
 
180
180
  # Write a TAMPERED trust.bundle: stored verified, evidence passing=false
181
- python3 - "$t_dir/.flow-agents/$slug/trust.bundle" "$claim_type" "$subject_type" << 'PY'
181
+ python3 - "$t_dir/.kontourai/flow-agents/$slug/trust.bundle" "$claim_type" "$subject_type" << 'PY'
182
182
  import json, sys
183
183
  claim_type = sys.argv[2]
184
184
  subject_type = sys.argv[3]
185
185
  bundle = {
186
- "schemaVersion": 3,
186
+ "schemaVersion": 5,
187
187
  "source": "flow-agents/workflow-sidecar",
188
188
  "claims": [{
189
189
  "id": "c1",
@@ -254,13 +254,16 @@ PY
254
254
  fi
255
255
  }
256
256
 
257
- # ─── Test 0: build.flow.json required:true confirmation ──────────────────────
257
+ # ─── Test 0: Flow Definition required:true confirmation ──────────────────────
258
258
  echo ""
259
- echo "=== 0. build.flow.json: confirm required:true for produced gates ==="
259
+ echo "=== 0. Flow Definitions: confirm required:true for produced gates ==="
260
260
 
261
261
  node -e "
262
262
  const fs = require('fs');
263
- const flow = JSON.parse(fs.readFileSync('$ROOT/kits/builder/flows/build.flow.json', 'utf8'));
263
+ const flows = [
264
+ JSON.parse(fs.readFileSync('$ROOT/kits/builder/flows/build.flow.json', 'utf8')),
265
+ JSON.parse(fs.readFileSync('$ROOT/kits/builder/flows/publish-learn.flow.json', 'utf8')),
266
+ ];
264
267
  const requiredTrue = [
265
268
  'selected-work',
266
269
  'pickup-probe-readiness',
@@ -271,26 +274,31 @@ node -e "
271
274
  ];
272
275
  const requiredFalse = ['policy-compliance'];
273
276
  let ok = true;
274
- for (const [gateName, gate] of Object.entries(flow.gates)) {
275
- for (const exp of gate.expects || []) {
277
+ for (const flow of flows) {
278
+ for (const [gateName, gate] of Object.entries(flow.gates || {})) {
279
+ for (const exp of gate.expects || []) {
276
280
  if (requiredTrue.includes(exp.id) && exp.required !== true) {
277
- console.error('FAIL: ' + exp.id + ' in ' + gateName + ' should be required:true, got ' + exp.required);
281
+ console.error('FAIL: ' + exp.id + ' in ' + flow.id + '/' + gateName + ' should be required:true, got ' + exp.required);
278
282
  ok = false;
279
283
  }
280
284
  if (requiredFalse.includes(exp.id) && exp.required !== false) {
281
- console.error('FAIL: ' + exp.id + ' in ' + gateName + ' should remain required:false (advisory), got ' + exp.required);
285
+ console.error('FAIL: ' + exp.id + ' in ' + flow.id + '/' + gateName + ' should remain required:false (advisory), got ' + exp.required);
282
286
  ok = false;
283
287
  }
288
+ }
284
289
  }
285
290
  }
286
291
  if (!ok) process.exit(1);
287
292
  " 2>/dev/null \
288
- && _pass "build.flow.json: 6 produced gates are required:true, policy-compliance is required:false" \
289
- || _fail "build.flow.json: required flag mismatch"
293
+ && _pass "Flow Definitions: 6 produced gates are required:true, policy-compliance is required:false" \
294
+ || _fail "Flow Definitions: required flag mismatch"
290
295
 
291
296
  node -e "
292
297
  const fs = require('fs');
293
- const flow = JSON.parse(fs.readFileSync('$ROOT/kits/builder/flows/build.flow.json', 'utf8'));
298
+ const flows = [
299
+ JSON.parse(fs.readFileSync('$ROOT/kits/builder/flows/build.flow.json', 'utf8')),
300
+ JSON.parse(fs.readFileSync('$ROOT/kits/builder/flows/publish-learn.flow.json', 'utf8')),
301
+ ];
294
302
  const producedIds = [
295
303
  'selected-work',
296
304
  'pickup-probe-readiness',
@@ -300,18 +308,20 @@ node -e "
300
308
  'learning-evidence',
301
309
  ];
302
310
  let ok = true;
303
- for (const [gateName, gate] of Object.entries(flow.gates)) {
304
- for (const exp of gate.expects || []) {
311
+ for (const flow of flows) {
312
+ for (const [gateName, gate] of Object.entries(flow.gates || {})) {
313
+ for (const exp of gate.expects || []) {
305
314
  if (producedIds.includes(exp.id) && exp.explore_hint) {
306
- console.error('FAIL: ' + exp.id + ' in ' + gateName + ' still has explore_hint (remove when producer exists)');
315
+ console.error('FAIL: ' + exp.id + ' in ' + flow.id + '/' + gateName + ' still has explore_hint (remove when producer exists)');
307
316
  ok = false;
308
317
  }
318
+ }
309
319
  }
310
320
  }
311
321
  if (!ok) process.exit(1);
312
322
  " 2>/dev/null \
313
- && _pass "build.flow.json: no explore_hint on produced gate entries" \
314
- || _fail "build.flow.json: produced gate entries still have explore_hint"
323
+ && _pass "Flow Definitions: no explore_hint on produced gate entries" \
324
+ || _fail "Flow Definitions: produced gate entries still have explore_hint"
315
325
 
316
326
  # ─── Tests 1–6: produce + tamper-block for each of the 6 claims ──────────────
317
327
 
@@ -158,13 +158,17 @@ echo "--- Installed Layout ---"
158
158
  for dir in \
159
159
  "$KIRO_DEST/agents" \
160
160
  "$BASE_DEST/.flow-agents" \
161
+ "$BASE_DEST/.kontourai/flow-agents" \
161
162
  "$CLAUDE_DEST/.claude/agents" \
162
163
  "$CLAUDE_DEST/.claude/skills" \
163
164
  "$CLAUDE_DEST/.flow-agents" \
165
+ "$CLAUDE_DEST/.kontourai/flow-agents" \
164
166
  "$CODEX_DEST/.codex/agents" \
165
167
  "$CODEX_DEST/.codex/skills" \
166
168
  "$CODEX_DEST/.flow-agents" \
167
- "$CODEX_FULL_DEST/.flow-agents"; do
169
+ "$CODEX_DEST/.kontourai/flow-agents" \
170
+ "$CODEX_FULL_DEST/.flow-agents" \
171
+ "$CODEX_FULL_DEST/.kontourai/flow-agents"; do
168
172
  if [[ -d "$dir" ]]; then
169
173
  _pass "$dir exists"
170
174
  else
@@ -218,7 +222,7 @@ fi
218
222
 
219
223
  if rg -F -q "console_telemetry_url=$LOCAL_KONTOUR_CONSOLE_URL" "$CODEX_INIT_DEST/scripts/telemetry/telemetry.conf" \
220
224
  && rg -q '^console_tenant_id=tenant-a$' "$CODEX_INIT_DEST/scripts/telemetry/telemetry.conf" \
221
- && [[ -f "$CODEX_INIT_DEST/.flow-agents/runtime/codex/activation.json" ]]; then
225
+ && [[ -f "$CODEX_INIT_DEST/.kontourai/flow-agents/projections/codex/activation.json" ]]; then
222
226
  _pass "flow-agents init persists Console config and activates Codex kits"
223
227
  else
224
228
  _fail "flow-agents init did not persist Console config or activate Codex kits"
@@ -226,6 +230,7 @@ fi
226
230
 
227
231
  if [[ -f "$BASE_INIT_DEST/AGENTS.md" ]] \
228
232
  && [[ -d "$BASE_INIT_DEST/.flow-agents" ]] \
233
+ && [[ -d "$BASE_INIT_DEST/.kontourai/flow-agents" ]] \
229
234
  && rg -F -q "console_telemetry_url=$LOCAL_KONTOUR_CONSOLE_URL" "$BASE_INIT_DEST/scripts/telemetry/telemetry.conf"; then
230
235
  _pass "flow-agents init default installs base AGENTS.md workspace contract"
231
236
  else
@@ -287,7 +292,7 @@ NODE
287
292
  else
288
293
  _fail "$dir is missing Kit Catalog or Builder Kit manifest"
289
294
  fi
290
- if [[ -f "$dir/kits/builder/flows/shape.flow.json" && -f "$dir/kits/builder/flows/build.flow.json" ]]; then
295
+ if [[ -f "$dir/kits/builder/flows/shape.flow.json" && -f "$dir/kits/builder/flows/build.flow.json" && -f "$dir/kits/builder/flows/publish-learn.flow.json" ]]; then
291
296
  _pass "$dir includes Builder Kit Flow Definitions"
292
297
  else
293
298
  _fail "$dir is missing Builder Kit Flow Definitions"
@@ -316,13 +321,13 @@ const dest = process.argv[2];
316
321
  const data = JSON.parse(fs.readFileSync(process.argv[3], "utf8"));
317
322
  if (data.selected_adapter !== "codex-local") throw new Error("codex-local was not selected");
318
323
  const ids = new Set((data.generated_runtime_files || []).map((item) => item.asset_id));
319
- for (const expected of ["builder.shape", "builder.build", "codex-local.activation"]) {
324
+ for (const expected of ["builder.shape", "builder.build", "builder.publish-learn", "codex-local.activation"]) {
320
325
  if (!ids.has(expected)) throw new Error(`missing generated runtime asset: ${expected}`);
321
326
  }
322
327
  for (const item of data.generated_runtime_files || []) {
323
328
  if (!fs.existsSync(path.join(dest, item.path))) throw new Error(`generated runtime file missing: ${item.path}`);
324
329
  }
325
- if (!fs.existsSync(path.join(dest, ".flow-agents/runtime/codex/activation.json"))) throw new Error("runtime activation manifest missing");
330
+ if (!fs.existsSync(path.join(dest, ".kontourai/flow-agents/projections/codex/activation.json"))) throw new Error("runtime activation manifest missing");
326
331
  console.log("ok");
327
332
  NODE
328
333
  then
@@ -335,7 +340,7 @@ if node - "$KIRO_DEST" "$BASE_DEST" "$CLAUDE_DEST" "$CODEX_DEST" <<'NODE'
335
340
  const fs = require("node:fs");
336
341
  const path = require("node:path");
337
342
  for (const root of process.argv.slice(2)) {
338
- for (const rel of ["kits/catalog.json", "kits/builder/kit.json", "kits/builder/flows/shape.flow.json", "kits/builder/flows/build.flow.json"]) {
343
+ for (const rel of ["kits/catalog.json", "kits/builder/kit.json", "kits/builder/flows/shape.flow.json", "kits/builder/flows/build.flow.json", "kits/builder/flows/publish-learn.flow.json"]) {
339
344
  JSON.parse(fs.readFileSync(path.join(root, rel), "utf8"));
340
345
  }
341
346
  }
@@ -367,25 +372,25 @@ else
367
372
  _pass "installed bundles are free of machine-local absolute paths"
368
373
  fi
369
374
 
370
- if [[ -f "$CLAUDE_DEST/.flow-agents/.gitkeep" ]]; then
375
+ if [[ -f "$CLAUDE_DEST/.kontourai/flow-agents/.gitkeep" ]]; then
371
376
  _pass "Claude Code task dir scaffold installed"
372
377
  else
373
378
  _fail "Claude Code task dir scaffold missing"
374
379
  fi
375
380
 
376
- if [[ -f "$CODEX_DEST/.flow-agents/.gitkeep" ]]; then
381
+ if [[ -f "$CODEX_DEST/.kontourai/flow-agents/.gitkeep" ]]; then
377
382
  _pass "Codex task dir scaffold installed"
378
383
  else
379
384
  _fail "Codex task dir scaffold missing"
380
385
  fi
381
386
 
382
- if [[ -f "$OPENCODE_DEST/.flow-agents/.gitkeep" ]]; then
387
+ if [[ -f "$OPENCODE_DEST/.kontourai/flow-agents/.gitkeep" ]]; then
383
388
  _pass "opencode task dir scaffold installed"
384
389
  else
385
390
  _fail "opencode task dir scaffold missing"
386
391
  fi
387
392
 
388
- if [[ -f "$PI_DEST/.flow-agents/.gitkeep" ]]; then
393
+ if [[ -f "$PI_DEST/.kontourai/flow-agents/.gitkeep" ]]; then
389
394
  _pass "pi task dir scaffold installed"
390
395
  else
391
396
  _fail "pi task dir scaffold missing"
@@ -417,9 +422,10 @@ else
417
422
  _fail "installed Claude permissions/statusline or Codex profile-v2 progress config is missing"
418
423
  fi
419
424
 
420
- if [[ -f "$CODEX_DEST/.codex/kdev.config.toml" && -f "$CODEX_DEST/.codex/kdev-br.config.toml" ]] \
421
- && rg -q 'approvals_reviewer = "auto_review"' "$CODEX_DEST/.codex/kdev.config.toml" \
422
- && rg -q 'model_provider = "amazon-bedrock"' "$CODEX_DEST/.codex/kdev-br.config.toml"; then
425
+ if [[ -f "$CODEX_DEST/.codex/builder.config.toml" && -f "$CODEX_DEST/.codex/personal.config.toml" ]] \
426
+ && [[ "$(find "$CODEX_DEST/.codex" -maxdepth 1 -name '*.config.toml' | wc -l | tr -d ' ')" == "2" ]] \
427
+ && rg -q 'Flow Agents Builder mode' "$CODEX_DEST/.codex/builder.config.toml" \
428
+ && rg -q 'knowledge-capture' "$CODEX_DEST/.codex/personal.config.toml"; then
423
429
  _pass "Codex install includes profile-v2 config files"
424
430
  else
425
431
  _fail "Codex install is missing profile-v2 config files"
@@ -517,7 +523,7 @@ const critique = {
517
523
  }],
518
524
  };
519
525
  function writeFixture(root) {
520
- const taskDir = path.join(root, ".flow-agents/installed-hook-demo");
526
+ const taskDir = path.join(root, ".kontourai/flow-agents/installed-hook-demo");
521
527
  fs.mkdirSync(taskDir, { recursive: true });
522
528
  fs.writeFileSync(path.join(taskDir, "state.json"), JSON.stringify(state), "utf8");
523
529
  fs.writeFileSync(path.join(taskDir, "critique.json"), JSON.stringify(critique), "utf8");
@@ -593,7 +599,7 @@ const critique = {
593
599
  critiques: [{ id: "oc-review", reviewer: "tool-code-reviewer", reviewed_at: "2026-06-01T00:01:00Z", verdict: "fail", summary: "Blocking.", findings: [{ id: "oc-open", severity: "high", status: "open", description: "Open finding." }] }],
594
600
  };
595
601
  function writeFixture(root) {
596
- const taskDir = path.join(root, ".flow-agents/opencode-hook-demo");
602
+ const taskDir = path.join(root, ".kontourai/flow-agents/opencode-hook-demo");
597
603
  fs.mkdirSync(taskDir, { recursive: true });
598
604
  fs.writeFileSync(path.join(taskDir, "state.json"), JSON.stringify(state), "utf8");
599
605
  fs.writeFileSync(path.join(taskDir, "critique.json"), JSON.stringify(critique), "utf8");
@@ -652,7 +658,7 @@ const critique = {
652
658
  critiques: [{ id: "pi-review", reviewer: "tool-code-reviewer", reviewed_at: "2026-06-01T00:01:00Z", verdict: "fail", summary: "Blocking.", findings: [{ id: "pi-open", severity: "high", status: "open", description: "Open finding." }] }],
653
659
  };
654
660
  function writeFixture(root) {
655
- const taskDir = path.join(root, ".flow-agents/pi-hook-demo");
661
+ const taskDir = path.join(root, ".kontourai/flow-agents/pi-hook-demo");
656
662
  fs.mkdirSync(taskDir, { recursive: true });
657
663
  fs.writeFileSync(path.join(taskDir, "state.json"), JSON.stringify(state), "utf8");
658
664
  fs.writeFileSync(path.join(taskDir, "critique.json"), JSON.stringify(critique), "utf8");
@@ -231,18 +231,18 @@ OPENCODE_USER="$TMPDIR_EVAL/user-opencode"
231
231
  # Create user-owned files (unknown to the bundle)
232
232
  mkdir -p "$CLAUDE_USER/.claude/custom"
233
233
  echo "# user custom agent" > "$CLAUDE_USER/.claude/custom/my-custom-agent.md"
234
- mkdir -p "$CLAUDE_USER/.flow-agents/my-session"
235
- echo '{"custom":"data"}' > "$CLAUDE_USER/.flow-agents/my-session/state.json"
234
+ mkdir -p "$CLAUDE_USER/.kontourai/flow-agents/my-session"
235
+ echo '{"custom":"data"}' > "$CLAUDE_USER/.kontourai/flow-agents/my-session/state.json"
236
236
 
237
237
  mkdir -p "$CODEX_USER/.codex/custom"
238
238
  printf 'name = "my-custom-agent"\n' > "$CODEX_USER/.codex/custom/my-custom-agent.toml"
239
- mkdir -p "$CODEX_USER/.flow-agents/my-session"
240
- echo '{"custom":"data"}' > "$CODEX_USER/.flow-agents/my-session/state.json"
239
+ mkdir -p "$CODEX_USER/.kontourai/flow-agents/my-session"
240
+ echo '{"custom":"data"}' > "$CODEX_USER/.kontourai/flow-agents/my-session/state.json"
241
241
 
242
242
  mkdir -p "$OPENCODE_USER/.opencode/custom"
243
243
  echo "# user custom agent" > "$OPENCODE_USER/.opencode/custom/my-custom-agent.md"
244
- mkdir -p "$OPENCODE_USER/.flow-agents/my-session"
245
- echo '{"custom":"data"}' > "$OPENCODE_USER/.flow-agents/my-session/state.json"
244
+ mkdir -p "$OPENCODE_USER/.kontourai/flow-agents/my-session"
245
+ echo '{"custom":"data"}' > "$OPENCODE_USER/.kontourai/flow-agents/my-session/state.json"
246
246
 
247
247
  # Modify an installed skill file to simulate user edits
248
248
  CLAUDE_INSTALLED_SKILL="$CLAUDE_USER/.claude/skills/plan-work/SKILL.md"
@@ -272,19 +272,19 @@ fi
272
272
  (cd "$ROOT_DIR/dist/opencode" && bash install.sh "$OPENCODE_USER" >/dev/null 2>&1) || true
273
273
 
274
274
  # Assert: user-owned unknown files survive
275
- if [[ -f "$CLAUDE_USER/.claude/custom/my-custom-agent.md" && -f "$CLAUDE_USER/.flow-agents/my-session/state.json" ]]; then
275
+ if [[ -f "$CLAUDE_USER/.claude/custom/my-custom-agent.md" && -f "$CLAUDE_USER/.kontourai/flow-agents/my-session/state.json" ]]; then
276
276
  _pass "claude-code re-install: user-owned files not removed by rsync"
277
277
  else
278
278
  _fail "claude-code re-install: user-owned files were removed"
279
279
  fi
280
280
 
281
- if [[ -f "$CODEX_USER/.codex/custom/my-custom-agent.toml" && -f "$CODEX_USER/.flow-agents/my-session/state.json" ]]; then
281
+ if [[ -f "$CODEX_USER/.codex/custom/my-custom-agent.toml" && -f "$CODEX_USER/.kontourai/flow-agents/my-session/state.json" ]]; then
282
282
  _pass "codex re-install: user-owned files not removed by rsync"
283
283
  else
284
284
  _fail "codex re-install: user-owned files were removed"
285
285
  fi
286
286
 
287
- if [[ -f "$OPENCODE_USER/.opencode/custom/my-custom-agent.md" && -f "$OPENCODE_USER/.flow-agents/my-session/state.json" ]]; then
287
+ if [[ -f "$OPENCODE_USER/.opencode/custom/my-custom-agent.md" && -f "$OPENCODE_USER/.kontourai/flow-agents/my-session/state.json" ]]; then
288
288
  _pass "opencode re-install: user-owned files not removed by rsync"
289
289
  else
290
290
  _fail "opencode re-install: user-owned files were removed"
@@ -528,7 +528,7 @@ fi
528
528
  # and point CLAUDE_PROJECT_DIR there so the hook can resolve its scripts.
529
529
  # This mirrors the real dogfood use case where the repo root has scripts/ from the bundle.
530
530
  DOGFOOD_WORKSPACE="$CLAUDE_IDEM" # reuse the installed workspace from the idempotent section
531
- mkdir -p "$DOGFOOD_WORKSPACE/.flow-agents"
531
+ mkdir -p "$DOGFOOD_WORKSPACE/.kontourai/flow-agents"
532
532
 
533
533
  if node - "$DOGFOOD_DEST2/.claude/settings.json" "$DOGFOOD_WORKSPACE" << 'NODE'
534
534
  const fs = require("node:fs");
@@ -537,7 +537,7 @@ const { spawnSync } = require("node:child_process");
537
537
  const [settingsPath, workspace] = process.argv.slice(2);
538
538
 
539
539
  // Write minimal fixtures for workflow-steering into the workspace
540
- const taskDir = path.join(workspace, ".flow-agents", "dogfood-hook-demo");
540
+ const taskDir = path.join(workspace, ".kontourai", "flow-agents", "dogfood-hook-demo");
541
541
  fs.mkdirSync(taskDir, { recursive: true });
542
542
  const state = {
543
543
  schema_version: "1.0",