@kontourai/flow-agents 2.3.0 → 2.4.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 (250) hide show
  1. package/.github/CODEOWNERS +8 -0
  2. package/.github/workflows/ci.yml +32 -0
  3. package/AGENTS.md +4 -4
  4. package/CHANGELOG.md +39 -0
  5. package/CONTEXT.md +14 -0
  6. package/README.md +9 -3
  7. package/agents/dev.json +1 -1
  8. package/agents/tool-code-reviewer.json +1 -1
  9. package/agents/tool-planner.json +3 -3
  10. package/agents/tool-verifier.json +3 -3
  11. package/build/src/cli/console-learning-projection.js +3 -2
  12. package/build/src/cli/init.js +104 -21
  13. package/build/src/cli/kit.js +37 -6
  14. package/build/src/cli/pull-work-provider.js +1 -1
  15. package/build/src/cli/usage-feedback.js +3 -3
  16. package/build/src/cli/validate-hook-influence.js +1 -0
  17. package/build/src/cli/validate-workflow-artifacts.js +22 -6
  18. package/build/src/cli/workflow-artifact-cleanup-audit.js +36 -2
  19. package/build/src/cli/workflow-sidecar.d.ts +14 -7
  20. package/build/src/cli/workflow-sidecar.js +792 -69
  21. package/build/src/flow-kit/validate.d.ts +23 -0
  22. package/build/src/flow-kit/validate.js +67 -1
  23. package/build/src/index.d.ts +1 -1
  24. package/build/src/index.js +1 -1
  25. package/build/src/lib/flow-resolver.d.ts +6 -4
  26. package/build/src/lib/flow-resolver.js +125 -58
  27. package/build/src/lib/local-artifact-root.d.ts +14 -2
  28. package/build/src/lib/local-artifact-root.js +22 -5
  29. package/build/src/lib/workflow-learning-projection.js +2 -2
  30. package/build/src/runtime-adapters.d.ts +12 -0
  31. package/build/src/runtime-adapters.js +56 -16
  32. package/build/src/tools/build-universal-bundles.js +49 -16
  33. package/build/src/tools/generate-context-map.js +10 -8
  34. package/build/src/tools/validate-source-tree.js +23 -1
  35. package/console.telemetry.json +22 -0
  36. package/context/contracts/artifact-contract.md +38 -7
  37. package/context/contracts/builder-kit-workflow-state-contract.md +3 -2
  38. package/context/contracts/decision-registry-contract.md +263 -0
  39. package/context/contracts/delivery-contract.md +1 -1
  40. package/context/contracts/planning-contract.md +2 -1
  41. package/context/contracts/review-contract.md +5 -3
  42. package/context/contracts/verification-contract.md +9 -1
  43. package/context/contracts/work-item-contract.md +1 -1
  44. package/context/deferred/parallelization.md +1 -1
  45. package/context/gate-awareness.md +4 -4
  46. package/context/scripts/git-status.sh +2 -2
  47. package/context/scripts/hooks/config-protection.js +502 -2
  48. package/context/scripts/hooks/lib/config-protection-remedies.js +69 -0
  49. package/context/scripts/hooks/run-hook.js +14 -1
  50. package/context/scripts/hooks/stop-goal-fit.js +1140 -99
  51. package/context/scripts/hooks/workflow-steering.js +212 -6
  52. package/docs/adr/0007-flow-skill-kit-tool-boundary.md +2 -0
  53. package/docs/adr/0015-flow-flow-agents-boundary-reconciliation.md +35 -0
  54. package/docs/adr/0019-kit-dependency-ownership.md +62 -0
  55. package/docs/adr/0020-trust-reconcile-manifest-and-claim-classification.md +290 -0
  56. package/docs/adr/0021-assignment-leases-and-stale-claim-takeover.md +221 -0
  57. package/docs/adr/0022-fail-closed-delivery-reconciliation-with-governed-exemptions.md +283 -0
  58. package/docs/agent-system-guidebook.md +3 -3
  59. package/docs/agent-usage-feedback-loop.md +6 -6
  60. package/docs/context-map.md +9 -7
  61. package/docs/decisions/decision-records.md +57 -0
  62. package/docs/decisions/index.md +14 -0
  63. package/docs/decisions/promotion-gate.md +52 -0
  64. package/docs/developer-architecture.md +1 -1
  65. package/docs/fixture-ownership.md +3 -0
  66. package/docs/flow-kit-repository-contract.md +5 -5
  67. package/docs/getting-started.md +12 -2
  68. package/docs/integrations/harness-install.md +2 -1
  69. package/docs/kit-authoring-guide.md +64 -5
  70. package/docs/knowledge-kit.md +5 -1
  71. package/docs/learnings/2026-07-improvement-program.md +203 -0
  72. package/docs/migrations.md +6 -5
  73. package/docs/north-star.md +2 -2
  74. package/docs/operating-layers.md +4 -3
  75. package/docs/repository-structure.md +5 -5
  76. package/docs/skills-map.md +8 -8
  77. package/docs/spec/runtime-hook-surface.md +19 -15
  78. package/docs/spikes/graph-provider-2026-07.md +155 -0
  79. package/docs/standards-register.md +7 -7
  80. package/docs/trust-anchor-adoption.md +105 -4
  81. package/docs/work-item-adapters.md +1 -1
  82. package/docs/workflow-artifact-lifecycle.md +72 -9
  83. package/docs/workflow-eval-strategy.md +3 -3
  84. package/docs/workflow-shared-contracts.md +1 -1
  85. package/docs/workflow-usage-guide.md +254 -21
  86. package/evals/acceptance/DEMO-false-completion.md +20 -11
  87. package/evals/acceptance/prove-capture-teeth-declared.sh +15 -15
  88. package/evals/acceptance/prove-capture-teeth.sh +11 -11
  89. package/evals/acceptance/test_kiro_harness.sh +1 -1
  90. package/evals/ci/antigaming-suite.sh +5 -0
  91. package/evals/ci/run-baseline.sh +65 -1
  92. package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/flows/review.flow.json +26 -0
  93. package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/kit.json +13 -0
  94. package/evals/fixtures/flow-kit-repository/valid-with-dependency/flows/review.flow.json +26 -0
  95. package/evals/fixtures/flow-kit-repository/valid-with-dependency/kit.json +13 -0
  96. package/evals/fixtures/hook-influence/cases.json +32 -0
  97. package/evals/fixtures/pull-work-provider/github-issues.json +6 -6
  98. package/evals/fixtures/trust-reconcile-exploits/fabricated-attestation.json +59 -0
  99. package/evals/fixtures/trust-reconcile-exploits/no-label-bypass.json +36 -0
  100. package/evals/fixtures/trust-reconcile-exploits/skip-assumed-bypass.json +59 -0
  101. package/evals/fixtures/trust-reconcile-exploits/status-misassertion.json +48 -0
  102. package/evals/fixtures/trust-reconcile-exploits/waived-command-check.json +44 -0
  103. package/evals/fixtures/trust-reconcile-mixed-bundle/mixed-bundle.json +159 -0
  104. package/evals/fixtures/trust-reconcile-ws3/ws3-bundle.json +920 -0
  105. package/evals/integration/test_actor_identity.sh +254 -0
  106. package/evals/integration/test_builder_step_producers.sh +33 -23
  107. package/evals/integration/test_bundle_install.sh +22 -16
  108. package/evals/integration/test_bundle_lifecycle.sh +11 -11
  109. package/evals/integration/test_captured_fail_reconciliation.sh +50 -50
  110. package/evals/integration/test_checkpoint_signing.sh +43 -0
  111. package/evals/integration/test_claim_lookup.sh +4 -4
  112. package/evals/integration/test_codex_hook_resolution.sh +114 -0
  113. package/evals/integration/test_command_log_concurrency.sh +8 -8
  114. package/evals/integration/test_command_log_fork_classification.sh +3 -3
  115. package/evals/integration/test_command_log_integrity.sh +16 -16
  116. package/evals/integration/test_console_learning_projection.sh +1 -1
  117. package/evals/integration/test_dual_emit_flow_step.sh +145 -0
  118. package/evals/integration/test_enforcer_expects_driven.sh +12 -12
  119. package/evals/integration/test_evidence_capture_hook.sh +14 -13
  120. package/evals/integration/test_fixture_retirement_audit.sh +2 -2
  121. package/evals/integration/test_flow_agents_statusline.sh +2 -2
  122. package/evals/integration/test_flow_kit_install_git.sh +52 -0
  123. package/evals/integration/test_flow_kit_repository.sh +2 -0
  124. package/evals/integration/test_flowdef_session_activation.sh +6 -6
  125. package/evals/integration/test_flowdef_union_floor_regression.sh +429 -0
  126. package/evals/integration/test_gate_bypass_chain.sh +52 -40
  127. package/evals/integration/test_gate_lockdown.sh +97 -73
  128. package/evals/integration/test_gate_review_inquiry_records.sh +3 -3
  129. package/evals/integration/test_goal_fit_escape_hatch.sh +10 -10
  130. package/evals/integration/test_goal_fit_ghost_session.sh +104 -0
  131. package/evals/integration/test_goal_fit_hook.sh +32 -32
  132. package/evals/integration/test_goal_fit_rederive.sh +9 -9
  133. package/evals/integration/test_hook_category_behaviors.sh +103 -0
  134. package/evals/integration/test_hook_influence_cases.sh +1 -0
  135. package/evals/integration/test_install_merge.sh +262 -1
  136. package/evals/integration/test_kit_identity_trust.sh +6 -6
  137. package/evals/integration/test_liveness_conflict_injection.sh +587 -0
  138. package/evals/integration/test_liveness_heartbeat.sh +677 -0
  139. package/evals/integration/test_liveness_verdict.sh +394 -0
  140. package/evals/integration/test_local_flow_kit_install.sh +15 -0
  141. package/evals/integration/test_phase_map_and_gate_claim.sh +63 -11
  142. package/evals/integration/test_promote_gate.sh +178 -0
  143. package/evals/integration/test_publish_delivery.sh +2 -2
  144. package/evals/integration/test_pull_work_liveness_preflight.sh +386 -0
  145. package/evals/integration/test_pull_work_provider.sh +2 -2
  146. package/evals/integration/test_reconcile_soundness.sh +4 -4
  147. package/evals/integration/test_resolvefirststep_security.sh +22 -0
  148. package/evals/integration/test_runtime_adapter_activation.sh +87 -18
  149. package/evals/integration/test_session_resume_roundtrip.sh +147 -0
  150. package/evals/integration/test_sidecar_field_preservation.sh +249 -0
  151. package/evals/integration/test_trust_reconcile.sh +2 -2
  152. package/evals/integration/test_trust_reconcile_manifest.sh +79 -0
  153. package/evals/integration/test_trust_reconcile_mixed_bundle.sh +96 -0
  154. package/evals/integration/test_trust_reconcile_negatives.sh +151 -0
  155. package/evals/integration/test_usage_feedback_global.sh +5 -5
  156. package/evals/integration/test_validate_artifacts_portability.sh +60 -0
  157. package/evals/integration/test_verify_cli.sh +2 -2
  158. package/evals/integration/test_veritas_governance_kit.sh +117 -0
  159. package/evals/integration/test_workflow_artifact_cleanup_audit.sh +26 -1
  160. package/evals/integration/test_workflow_artifacts.sh +33 -0
  161. package/evals/integration/test_workflow_sidecar_writer.sh +723 -74
  162. package/evals/integration/test_workflow_steering_hook.sh +175 -5
  163. package/evals/lib/codex-provider.sh +1 -1
  164. package/evals/lib/node.sh +19 -1
  165. package/evals/run.sh +22 -0
  166. package/evals/static/test_decisions.sh +150 -0
  167. package/evals/static/test_flowdef_codeowners_coverage.sh +56 -0
  168. package/evals/static/test_package.sh +19 -10
  169. package/evals/static/test_universal_bundles.sh +48 -3
  170. package/evals/static/test_workflow_skills.sh +41 -8
  171. package/kits/builder/flows/build.flow.json +3 -74
  172. package/kits/builder/flows/publish-learn.flow.json +90 -0
  173. package/kits/builder/kit.json +11 -0
  174. package/kits/builder/skills/builder-shape/SKILL.md +1 -1
  175. package/kits/builder/skills/deliver/SKILL.md +13 -11
  176. package/kits/builder/skills/design-probe/SKILL.md +4 -4
  177. package/kits/builder/skills/evidence-gate/SKILL.md +26 -1
  178. package/kits/builder/skills/execute-plan/SKILL.md +2 -2
  179. package/kits/builder/skills/fix-bug/SKILL.md +2 -0
  180. package/kits/builder/skills/gate-review/SKILL.md +6 -6
  181. package/kits/builder/skills/idea-to-backlog/SKILL.md +1 -1
  182. package/kits/builder/skills/learning-review/SKILL.md +7 -7
  183. package/kits/builder/skills/pickup-probe/SKILL.md +5 -4
  184. package/kits/builder/skills/plan-work/SKILL.md +27 -5
  185. package/kits/builder/skills/pull-work/SKILL.md +80 -5
  186. package/kits/builder/skills/release-readiness/SKILL.md +4 -4
  187. package/kits/builder/skills/review-work/SKILL.md +24 -1
  188. package/kits/builder/skills/tdd-workflow/SKILL.md +2 -0
  189. package/kits/builder/skills/verify-work/SKILL.md +8 -1
  190. package/kits/catalog.json +6 -0
  191. package/kits/veritas-governance/adapter/readiness-to-trust-bundle.mjs +178 -0
  192. package/kits/veritas-governance/docs/README.md +75 -0
  193. package/kits/veritas-governance/fixtures/readiness/not-ready.readiness-report.json +4645 -0
  194. package/kits/veritas-governance/fixtures/readiness/ready.readiness-report.json +4403 -0
  195. package/kits/veritas-governance/flows/readiness-check.flow.json +35 -0
  196. package/kits/veritas-governance/kit.json +16 -0
  197. package/package.json +8 -4
  198. package/packaging/README.md +2 -2
  199. package/packaging/conformance/fixtures/config-protection--allow-read-state-json.json +20 -0
  200. package/packaging/conformance/fixtures/config-protection--block-write-state-json.json +20 -0
  201. package/packaging/conformance/fixtures/stop-goal-fit--block-bundle-disputed-claim.json +1 -1
  202. package/packaging/conformance/fixtures/stop-goal-fit--block-capture-contradicts-claimed-pass.json +1 -1
  203. package/packaging/manifest.json +9 -10
  204. package/schemas/decision-record.schema.json +109 -0
  205. package/schemas/workflow-evidence.schema.json +1 -1
  206. package/schemas/workflow-state.schema.json +5 -0
  207. package/scripts/README.md +8 -3
  208. package/scripts/check-content-boundary.cjs +1 -1
  209. package/scripts/check-decisions.cjs +356 -0
  210. package/scripts/ci/derive-claim-status.mjs +74 -0
  211. package/scripts/ci/trust-reconcile.js +436 -79
  212. package/scripts/git-status.sh +2 -2
  213. package/scripts/hooks/claude-telemetry-hook.js +37 -3
  214. package/scripts/hooks/codex-telemetry-hook.js +36 -2
  215. package/scripts/hooks/config-protection.js +102 -30
  216. package/scripts/hooks/evidence-capture.js +3 -3
  217. package/scripts/hooks/lib/actor-identity.js +368 -0
  218. package/scripts/hooks/lib/config-protection-remedies.js +69 -0
  219. package/scripts/hooks/lib/liveness-heartbeat.js +361 -0
  220. package/scripts/hooks/lib/liveness-policy.js +127 -0
  221. package/scripts/hooks/lib/liveness-read.js +105 -12
  222. package/scripts/hooks/lib/liveness-write.js +46 -0
  223. package/scripts/hooks/lib/local-artifact-paths.js +12 -6
  224. package/scripts/hooks/opencode-telemetry-hook.js +27 -1
  225. package/scripts/hooks/pi-telemetry-hook.js +27 -1
  226. package/scripts/hooks/stop-goal-fit.js +157 -26
  227. package/scripts/hooks/workflow-steering.js +77 -3
  228. package/scripts/install-codex-home.sh +138 -38
  229. package/scripts/statusline/flow-agents-statusline.js +2 -2
  230. package/src/cli/console-learning-projection.ts +3 -2
  231. package/src/cli/init.ts +101 -21
  232. package/src/cli/kit.ts +37 -6
  233. package/src/cli/public-api.test.mjs +58 -6
  234. package/src/cli/pull-work-provider.ts +1 -1
  235. package/src/cli/trust-bundle-policy-order.test.mjs +87 -0
  236. package/src/cli/usage-feedback.ts +3 -3
  237. package/src/cli/validate-hook-influence.ts +1 -0
  238. package/src/cli/validate-workflow-artifacts.ts +22 -6
  239. package/src/cli/veritas-readiness-adapter.test.mjs +267 -0
  240. package/src/cli/workflow-artifact-cleanup-audit.ts +35 -2
  241. package/src/cli/workflow-sidecar.ts +795 -71
  242. package/src/flow-kit/validate.ts +74 -1
  243. package/src/index.ts +6 -2
  244. package/src/lib/flow-resolver.ts +123 -55
  245. package/src/lib/local-artifact-root.ts +24 -5
  246. package/src/lib/workflow-learning-projection.ts +2 -2
  247. package/src/runtime-adapters.ts +61 -15
  248. package/src/tools/build-universal-bundles.ts +49 -16
  249. package/src/tools/generate-context-map.ts +10 -8
  250. package/src/tools/validate-source-tree.ts +23 -1
@@ -363,6 +363,46 @@ else
363
363
  _fail "--global: merge into global settings failed or user key/hook lost"
364
364
  fi
365
365
 
366
+ # Regression guard: --global hook commands must resolve regardless of which
367
+ # project is open. The bundle template resolves scripts/ via
368
+ # ${CLAUDE_PROJECT_DIR:-$(pwd)}, which only exists for project-scoped installs
369
+ # (installBundle rsyncs scripts/ alongside .claude/). A --global install must
370
+ # rewrite that to an absolute path, or every FA hook silently MODULE_NOT_FOUNDs
371
+ # in any project other than this package's own checkout.
372
+ if [[ -f "$GLOBAL_SETTINGS_JSON" ]] && node - "$GLOBAL_SETTINGS_JSON" << 'NODE'
373
+ const fs = require("node:fs");
374
+ const s = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
375
+ const hooks = s.hooks || {};
376
+ const commands = Object.values(hooks).flat().flatMap((g) => (g.hooks || []).map((h) => String(h.command || "")));
377
+ const faCommands = commands.filter((c) => c.includes("claude-hook-adapter.js") || c.includes("claude-telemetry-hook.js"));
378
+ if (faCommands.length === 0) throw new Error("no FA hook commands found to check");
379
+ for (const c of faCommands) {
380
+ if (c.includes("CLAUDE_PROJECT_DIR")) throw new Error("FA hook command still depends on CLAUDE_PROJECT_DIR (breaks outside this package's own project): " + c);
381
+ const m = c.match(/node "([^"]+\/scripts\/hooks\/[^"]+\.js)"/);
382
+ if (!m) throw new Error("FA hook command has no absolute scripts/hooks path: " + c);
383
+ if (!fs.existsSync(m[1])) throw new Error("FA hook command points at a path that does not exist: " + m[1]);
384
+ }
385
+ console.log("ok");
386
+ NODE
387
+ then
388
+ _pass "--global: FA hook commands use an absolute, resolvable path (no CLAUDE_PROJECT_DIR dependency)"
389
+ else
390
+ _fail "--global: FA hook commands are not resolvable outside this package's own project directory"
391
+ fi
392
+
393
+ # Regression guard: --global must also sync skills and agents so newly added
394
+ # Builder Kit skills don't require a full reinstall to pick up.
395
+ if [[ -d "$GLOBAL_SETTINGS_DIR/skills/plan-work" && -f "$GLOBAL_SETTINGS_DIR/skills/plan-work/SKILL.md" ]]; then
396
+ _pass "--global: skills synced into global destination"
397
+ else
398
+ _fail "--global: skills were not synced into global destination"
399
+ fi
400
+ if [[ -d "$GLOBAL_SETTINGS_DIR/agents" && -n "$(ls -A "$GLOBAL_SETTINGS_DIR/agents" 2>/dev/null)" ]]; then
401
+ _pass "--global: agents synced into global destination"
402
+ else
403
+ _fail "--global: agents were not synced into global destination"
404
+ fi
405
+
366
406
  echo ""
367
407
 
368
408
  # ─── Scenario 6: Manual proof (user-visible) ─────────────────────────────────
@@ -870,6 +910,21 @@ fi
870
910
 
871
911
  # ─── codex-home: CH1: merge — user Stop hook survives install-codex-home ─────
872
912
  echo "=== Install Merge-Aware Tests (codex-home) ==="
913
+ echo ""
914
+ echo "--- CH0: codex-home default destination honors CODEX_HOME ---"
915
+
916
+ CH0_CODEX_HOME="$TMPDIR_EVAL/codex-home-ch0"
917
+ CH0_REAL_HOME="$TMPDIR_EVAL/fake-real-codex-ch0"
918
+ mkdir -p "$CH0_CODEX_HOME" "$CH0_REAL_HOME"
919
+
920
+ CODEX_HOME="$CH0_CODEX_HOME" CODEX_REAL_HOME="$CH0_REAL_HOME" bash "$ROOT_DIR/scripts/install-codex-home.sh" >/dev/null 2>&1
921
+
922
+ if [[ -f "$CH0_CODEX_HOME/hooks.json" && -f "$CH0_CODEX_HOME/.flow-agents/install.json" && ! -e "$TMPDIR_EVAL/.codex/hooks.json" ]]; then
923
+ _pass "CH0: install-codex-home defaults to CODEX_HOME"
924
+ else
925
+ _fail "CH0: install-codex-home did not default to CODEX_HOME"
926
+ fi
927
+
873
928
  echo ""
874
929
  echo "--- CH1: codex-home merge — seed user Stop hook → install → user hook survives + FA hooks present ---"
875
930
 
@@ -994,6 +1049,160 @@ fi
994
1049
 
995
1050
  echo ""
996
1051
 
1052
+ # ─── codex-home: CH4: real home preservation ────────────────────────────────
1053
+ echo "--- CH4: codex-home preserves user config, profiles, hooks, local kit state, and user skills ---"
1054
+
1055
+ CH4_DEST="$TMPDIR_EVAL/codex-home-ch4"
1056
+ mkdir -p "$CH4_DEST/kits/local/repositories/user-kit" "$CH4_DEST/sk""ills/user-owned-skill" "$CH4_DEST/ag""ents"
1057
+
1058
+ cat > "$CH4_DEST/config.toml" << 'EOF_CFG'
1059
+ model = "user-model"
1060
+ EOF_CFG
1061
+
1062
+ cat > "$CH4_DEST/custom.config.toml" << 'EOF_CFG'
1063
+ model = "user-profile-model"
1064
+ EOF_CFG
1065
+ cat > "$CH4_DEST/builder.config.toml" << 'EOF_CFG'
1066
+ # Generated from packaging/manifest.json. Edit the manifest, not this file.
1067
+ model = "old-builder-profile"
1068
+ EOF_CFG
1069
+ cat > "$CH4_DEST/retired-generated.config.toml" << 'EOF_CFG'
1070
+ # Generated from packaging/manifest.json. Edit the manifest, not this file.
1071
+ model = "old-generated-profile"
1072
+ EOF_CFG
1073
+
1074
+ cat > "$CH4_DEST/AGENTS.md" << 'EOF_AGENTS'
1075
+ # User Codex Instructions
1076
+ EOF_AGENTS
1077
+
1078
+ cat > "$CH4_DEST/hooks.json" << 'JSON'
1079
+ {
1080
+ "hooks": {
1081
+ "Stop": [
1082
+ {
1083
+ "hooks": [
1084
+ {
1085
+ "type": "command",
1086
+ "command": "echo ch4-user-stop-hook"
1087
+ }
1088
+ ]
1089
+ }
1090
+ ]
1091
+ }
1092
+ }
1093
+ JSON
1094
+
1095
+ cat > "$CH4_DEST/kits/local/installed-kits.json" << 'JSON'
1096
+ {
1097
+ "kits": [
1098
+ {
1099
+ "id": "user-kit",
1100
+ "source": "local-user-source",
1101
+ "state": "installed"
1102
+ }
1103
+ ]
1104
+ }
1105
+ JSON
1106
+ cat > "$CH4_DEST/kits/local/repositories/user-kit/kit.json" << 'JSON'
1107
+ {"id":"user-kit","name":"User Kit"}
1108
+ JSON
1109
+ cat > "$CH4_DEST/sk""ills/user-owned-skill/SKILL.md" << 'EOF_SKILL'
1110
+ # User Owned Skill
1111
+ EOF_SKILL
1112
+ cat > "$CH4_DEST/ag""ents/user-owned-agent.toml" << 'EOF_AGENT'
1113
+ name = "user-owned-agent"
1114
+ EOF_AGENT
1115
+
1116
+ CODEX_REAL_HOME="$TMPDIR_EVAL/fake-real-codex" bash "$ROOT_DIR/scripts/install-codex-home.sh" "$CH4_DEST" >/dev/null 2>&1
1117
+
1118
+ if grep -q 'user-model' "$CH4_DEST/config.toml" \
1119
+ && grep -q 'user-profile-model' "$CH4_DEST/custom.config.toml" \
1120
+ && grep -q 'User Codex Instructions' "$CH4_DEST/AGENTS.md"; then
1121
+ _pass "CH4: user-owned config.toml, profile, and AGENTS.md preserved"
1122
+ else
1123
+ _fail "CH4: user-owned config.toml, profile, or AGENTS.md was overwritten"
1124
+ fi
1125
+
1126
+ if [[ -f "$CH4_DEST/builder.config.toml" && -f "$CH4_DEST/personal.config.toml" ]] \
1127
+ && grep -q 'Flow Agents Builder mode' "$CH4_DEST/builder.config.toml" \
1128
+ && grep -q 'knowledge-capture' "$CH4_DEST/personal.config.toml"; then
1129
+ _pass "CH4: generated Codex profiles are seeded or refreshed"
1130
+ else
1131
+ _fail "CH4: generated Codex profiles were not seeded or refreshed"
1132
+ fi
1133
+
1134
+ if [[ ! -f "$CH4_DEST/retired-generated.config.toml" ]]; then
1135
+ _pass "CH4: retired generated Codex profiles are removed"
1136
+ else
1137
+ _fail "CH4: retired generated Codex profiles were not removed"
1138
+ fi
1139
+
1140
+ if [[ -f "$CH4_DEST/kits/local/installed-kits.json" && -f "$CH4_DEST/kits/local/repositories/user-kit/kit.json" ]] \
1141
+ && node - "$CH4_DEST/kits/local/installed-kits.json" << 'NODE'
1142
+ const fs = require("node:fs");
1143
+ const registry = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
1144
+ if (!Array.isArray(registry.kits) || !registry.kits.some((kit) => kit.id === "user-kit")) {
1145
+ throw new Error("user kit registry entry missing");
1146
+ }
1147
+ console.log("ok");
1148
+ NODE
1149
+ then
1150
+ _pass "CH4: kits/local registry and repository preserved"
1151
+ else
1152
+ _fail "CH4: kits/local registry or repository was removed"
1153
+ fi
1154
+
1155
+ if [[ -f "$CH4_DEST/sk""ills/search-first/SKILL.md" && -f "$CH4_DEST/sk""ills/plan-work/SKILL.md" && -f "$CH4_DEST/sk""ills/user-owned-skill/SKILL.md" ]]; then
1156
+ _pass "CH4: root, Builder Kit workflow, and user-owned skills coexist in flattened Codex skills"
1157
+ else
1158
+ _fail "CH4: root skill, Builder Kit workflow skill, or user-owned skill missing from flattened Codex skills"
1159
+ fi
1160
+
1161
+ if [[ -f "$CH4_DEST/scripts/install-merge.js" && -f "$CH4_DEST/build/src/cli/kit.js" && -f "$CH4_DEST/ag""ents/tool-worker.toml" && -f "$CH4_DEST/ag""ents/user-owned-agent.toml" && -f "$CH4_DEST/hooks.json" ]] \
1162
+ && node - "$CH4_DEST/hooks.json" << 'NODE'
1163
+ const fs = require("node:fs");
1164
+ const s = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
1165
+ const stopGroups = (s.hooks || {}).Stop || [];
1166
+ const hasUser = stopGroups.some((g) => (g.hooks || []).some((h) => String(h.command || "").includes("echo ch4-user-stop-hook")));
1167
+ const hasFA = Object.values(s.hooks || {}).flat().some((g) => (g.hooks || []).some((h) => String(h.statusMessage || "").includes("Recording Flow Agents telemetry")));
1168
+ if (!hasUser) throw new Error("user hook missing");
1169
+ if (!hasFA) throw new Error("FA hooks missing");
1170
+ console.log("ok");
1171
+ NODE
1172
+ then
1173
+ _pass "CH4: Flow Agents bundle scripts, build artifacts, generated/user agents, and merged hooks installed"
1174
+ else
1175
+ _fail "CH4: bundle scripts, build artifacts, generated/user agents, or merged hooks missing"
1176
+ fi
1177
+
1178
+ if node "$CH4_DEST/scripts/kit.js" list --dest "$CH4_DEST" >/dev/null 2>&1; then
1179
+ _pass "CH4: installed scripts/kit.js runs with installed build bundle"
1180
+ else
1181
+ _fail "CH4: installed scripts/kit.js could not run with installed build bundle"
1182
+ fi
1183
+
1184
+ echo ""
1185
+
1186
+ # ─── codex-home: CH5: destination symlink containment ───────────────────────
1187
+ echo "--- CH5: codex-home refuses managed destination symlinks ---"
1188
+
1189
+ for CH5_REL in scripts kits sk""ills hooks.json; do
1190
+ CH5_DEST="$TMPDIR_EVAL/codex-home-ch5-${CH5_REL//\//-}"
1191
+ CH5_OUTSIDE="$TMPDIR_EVAL/codex-home-ch5-outside-${CH5_REL//\//-}"
1192
+ mkdir -p "$CH5_DEST" "$CH5_OUTSIDE"
1193
+ ln -s "$CH5_OUTSIDE" "$CH5_DEST/$CH5_REL"
1194
+ if CODEX_REAL_HOME="$TMPDIR_EVAL/fake-real-codex" bash "$ROOT_DIR/scripts/install-codex-home.sh" "$CH5_DEST" >"$TMPDIR_EVAL/ch5.out" 2>&1; then
1195
+ _fail "CH5: install unexpectedly succeeded with symlinked destination $CH5_REL"
1196
+ elif grep -q "refusing to write through symlink" "$TMPDIR_EVAL/ch5.out" \
1197
+ && [[ -z "$(find "$CH5_OUTSIDE" -mindepth 1 -maxdepth 1 -print -quit)" ]]; then
1198
+ _pass "CH5: install refuses symlinked destination $CH5_REL without writing outside"
1199
+ else
1200
+ _fail "CH5: symlinked destination $CH5_REL did not fail closed"
1201
+ fi
1202
+ done
1203
+
1204
+ echo ""
1205
+
997
1206
  # ─── opencode --global: OG1: seed user key → install --global → key survives + $schema + stamp ─
998
1207
  echo "=== Install Merge-Aware Tests (--global runtimes) ==="
999
1208
  echo ""
@@ -1079,7 +1288,11 @@ CG1_DEST="$TMPDIR_EVAL/codex-global-cg1"
1079
1288
  mkdir -p "$CG1_DEST"
1080
1289
 
1081
1290
  # Run init --global --runtime codex with dest override (sandbox isolation)
1082
- CODEX_REAL_HOME="$TMPDIR_EVAL/fake-real-codex" node "$ROOT_DIR/build/src/cli.js" init --runtime codex --global --dest "$CG1_DEST" --yes >/dev/null 2>&1 || true
1291
+ if CODEX_REAL_HOME="$TMPDIR_EVAL/fake-real-codex" node "$ROOT_DIR/build/src/cli.js" init --runtime codex --global --dest "$CG1_DEST" --activate-kits --yes >/dev/null 2>&1; then
1292
+ _pass "CG1: codex --global --activate-kits command succeeds"
1293
+ else
1294
+ _fail "CG1: codex --global --activate-kits command failed"
1295
+ fi
1083
1296
 
1084
1297
  # Assert: FA hooks present in $DEST/hooks.json
1085
1298
  if node - "$CG1_DEST/hooks.json" << 'NODE'
@@ -1112,6 +1325,54 @@ else
1112
1325
  _fail "CG1: codex --global: version stamp missing or wrong"
1113
1326
  fi
1114
1327
 
1328
+ if [[ -f "$CG1_DEST/.kontourai/flow-agents/projections/codex/activation.json" ]]; then
1329
+ _pass "CG1: codex --global --activate-kits writes activation output under target Codex home"
1330
+ else
1331
+ _fail "CG1: codex --global --activate-kits did not write activation output under target Codex home"
1332
+ fi
1333
+
1334
+ echo ""
1335
+
1336
+ # ─── codex --global: CG1B: default CODEX_HOME + --dest override precedence ───
1337
+ echo "--- CG1B: codex --global default honors CODEX_HOME and --dest overrides ---"
1338
+
1339
+ CG1B_CODEX_HOME="$TMPDIR_EVAL/codex-global-cg1b-codex-home"
1340
+ CG1B_OVERRIDE="$TMPDIR_EVAL/codex-global-cg1b-override"
1341
+ mkdir -p "$CG1B_CODEX_HOME" "$CG1B_OVERRIDE"
1342
+
1343
+ if CODEX_HOME="$CG1B_CODEX_HOME" CODEX_REAL_HOME="$TMPDIR_EVAL/fake-real-codex" node "$ROOT_DIR/build/src/cli.js" init --runtime codex --global --yes >/dev/null 2>&1; then
1344
+ _pass "CG1B: codex --global without --dest command succeeds"
1345
+ else
1346
+ _fail "CG1B: codex --global without --dest command failed"
1347
+ fi
1348
+
1349
+ if [[ -f "$CG1B_CODEX_HOME/hooks.json" && -f "$CG1B_CODEX_HOME/.flow-agents/install.json" ]]; then
1350
+ _pass "CG1B: codex --global without --dest installs into CODEX_HOME"
1351
+ else
1352
+ _fail "CG1B: codex --global without --dest did not install into CODEX_HOME"
1353
+ fi
1354
+
1355
+ rm -rf "$CG1B_CODEX_HOME"
1356
+ mkdir -p "$CG1B_CODEX_HOME"
1357
+
1358
+ if CODEX_HOME="$CG1B_CODEX_HOME" CODEX_REAL_HOME="$TMPDIR_EVAL/fake-real-codex" node "$ROOT_DIR/build/src/cli.js" init --runtime codex --global --dest "$CG1B_OVERRIDE" --yes >/dev/null 2>&1; then
1359
+ _pass "CG1B: codex --global --dest command succeeds"
1360
+ else
1361
+ _fail "CG1B: codex --global --dest command failed"
1362
+ fi
1363
+
1364
+ if [[ -f "$CG1B_OVERRIDE/hooks.json" && -f "$CG1B_OVERRIDE/.flow-agents/install.json" ]]; then
1365
+ _pass "CG1B: codex --global --dest overrides CODEX_HOME"
1366
+ else
1367
+ _fail "CG1B: codex --global --dest did not override CODEX_HOME"
1368
+ fi
1369
+
1370
+ if [[ ! -e "$CG1B_CODEX_HOME/hooks.json" && ! -e "$CG1B_CODEX_HOME/.flow-agents/install.json" ]]; then
1371
+ _pass "CG1B: codex --global --dest did not write install artifacts into CODEX_HOME"
1372
+ else
1373
+ _fail "CG1B: codex --global --dest wrote install artifacts into CODEX_HOME"
1374
+ fi
1375
+
1115
1376
  echo ""
1116
1377
 
1117
1378
  # ─── codex --global: CG2: fresh install clean ────────────────────────────────
@@ -44,11 +44,11 @@ const fs = require('fs');
44
44
  // argv[0]=node, argv[1]="-", argv[2]=file path
45
45
  const bundlePath = process.argv[2];
46
46
  const bundle = {
47
- schemaVersion: 3, source: "test-fixture",
47
+ schemaVersion: 5, source: "test-fixture",
48
48
  claims: [{
49
49
  id: "c-knowledge-1", claimType: "knowledge.verify.tests",
50
50
  subjectType: "flow-step", subjectId: "test-slug/knowledge-ev",
51
- surface: "flow-agents.workflow", fieldOrBehavior: "knowledge verification",
51
+ facet: "flow-agents.workflow", fieldOrBehavior: "knowledge verification",
52
52
  value: "pass", status: "verified",
53
53
  createdAt: "2026-06-27T00:00:00Z", updatedAt: "2026-06-27T00:00:00Z",
54
54
  impactLevel: "high", verificationPolicyId: "policy:knowledge.verify.tests"
@@ -62,11 +62,11 @@ node - "$TMP/builder.bundle" << 'NODE'
62
62
  const fs = require('fs');
63
63
  const bundlePath = process.argv[2];
64
64
  const bundle = {
65
- schemaVersion: 3, source: "test-fixture",
65
+ schemaVersion: 5, source: "test-fixture",
66
66
  claims: [{
67
67
  id: "c-builder-1", claimType: "builder.verify.tests",
68
68
  subjectType: "flow-step", subjectId: "test-slug/builder-ev",
69
- surface: "flow-agents.workflow", fieldOrBehavior: "builder verification",
69
+ facet: "flow-agents.workflow", fieldOrBehavior: "builder verification",
70
70
  value: "pass", status: "verified",
71
71
  createdAt: "2026-06-27T00:00:00Z", updatedAt: "2026-06-27T00:00:00Z",
72
72
  impactLevel: "high", verificationPolicyId: "policy:builder.verify.tests"
@@ -80,11 +80,11 @@ node - "$TMP/workflow-only.bundle" << 'NODE'
80
80
  const fs = require('fs');
81
81
  const bundlePath = process.argv[2];
82
82
  const bundle = {
83
- schemaVersion: 3, source: "test-fixture",
83
+ schemaVersion: 5, source: "test-fixture",
84
84
  claims: [{
85
85
  id: "c-wf-1", claimType: "workflow.check.build",
86
86
  subjectType: "workflow-check", subjectId: "test-slug/build",
87
- surface: "flow-agents.workflow", fieldOrBehavior: "build check",
87
+ facet: "flow-agents.workflow", fieldOrBehavior: "build check",
88
88
  value: "pass", status: "verified",
89
89
  createdAt: "2026-06-27T00:00:00Z", updatedAt: "2026-06-27T00:00:00Z",
90
90
  impactLevel: "high", verificationPolicyId: "policy:workflow.check.build"