@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
@@ -42,11 +42,11 @@ trap cleanup EXIT
42
42
  # ─── Helper: seed a delivered (terminal) workflow artifact ────────────────────
43
43
  seed_delivered() { # $1=dir $2=slug
44
44
  local p="$1" slug="$2"
45
- mkdir -p "$p/.flow-agents/$slug"
45
+ mkdir -p "$p/.kontourai/flow-agents/$slug"
46
46
  printf '# Repo\n' > "$p/AGENTS.md"
47
47
  printf '%s' "{\"schema_version\":\"1.0\",\"task_slug\":\"$slug\",\"status\":\"delivered\",\"phase\":\"done\",\"updated_at\":\"2026-06-27T00:00:00Z\",\"next_action\":{\"status\":\"done\",\"summary\":\"done\"}}" \
48
- > "$p/.flow-agents/$slug/state.json"
49
- cat > "$p/.flow-agents/$slug/$slug--deliver.md" << MD
48
+ > "$p/.kontourai/flow-agents/$slug/state.json"
49
+ cat > "$p/.kontourai/flow-agents/$slug/$slug--deliver.md" << MD
50
50
  # $slug
51
51
 
52
52
  branch: main
@@ -71,7 +71,7 @@ write_kit_pass_bundle() { # $1=bundle_path $2=slug $3=claim_value(opt)
71
71
  import json, sys
72
72
  bundle_path, slug, claim_val = sys.argv[1], sys.argv[2], sys.argv[3]
73
73
  bundle = {
74
- "schemaVersion": 3, "source": "flow-agents/workflow-sidecar",
74
+ "schemaVersion": 5, "source": "flow-agents/workflow-sidecar",
75
75
  "claims": [{
76
76
  "id": "c1", "subjectId": slug + "/tests", "subjectType": "flow-step",
77
77
  "claimType": "builder.verify.tests",
@@ -131,10 +131,10 @@ T1="$TMP/t1-bypass"
131
131
  seed_delivered "$T1" "bypass-kit"
132
132
 
133
133
  # NO active_flow_id in current.json
134
- printf '%s' '{"artifact_dir":"bypass-kit"}' > "$T1/.flow-agents/current.json"
134
+ printf '%s' '{"artifact_dir":"bypass-kit"}' > "$T1/.kontourai/flow-agents/current.json"
135
135
 
136
- write_kit_pass_bundle "$T1/.flow-agents/bypass-kit/trust.bundle" "bypass-kit"
137
- write_fail_log "$T1/.flow-agents/bypass-kit/command-log.jsonl"
136
+ write_kit_pass_bundle "$T1/.kontourai/flow-agents/bypass-kit/trust.bundle" "bypass-kit"
137
+ write_fail_log "$T1/.kontourai/flow-agents/bypass-kit/command-log.jsonl"
138
138
 
139
139
  echo ""
140
140
  echo "--- 1a. PRE-FIX simulation: show the gate was blind ---"
@@ -208,7 +208,7 @@ seed_delivered "$T2" "nondeclared"
208
208
 
209
209
  # current.json: active flow (builder.build/verify)
210
210
  printf '%s' '{"artifact_dir":"nondeclared","active_flow_id":"builder.build","active_step_id":"verify"}' \
211
- > "$T2/.flow-agents/current.json"
211
+ > "$T2/.kontourai/flow-agents/current.json"
212
212
 
213
213
  # Fake flow defs dir (safe, not agent-writable)
214
214
  FLOW_DEFS_DIR="$TMP/flows"
@@ -238,11 +238,11 @@ cat > "$FLOW_DEFS_DIR/builder.build.flow.json" << 'FLOWJSON'
238
238
  FLOWJSON
239
239
 
240
240
  # Bundle: agent-chosen NON-declared claimType (e.g. "acme.custom.verify") claiming npm test passed
241
- python3 - "$T2/.flow-agents/nondeclared/trust.bundle" "nondeclared" << 'PY'
241
+ python3 - "$T2/.kontourai/flow-agents/nondeclared/trust.bundle" "nondeclared" << 'PY'
242
242
  import json, sys
243
243
  bundle_path, slug = sys.argv[1], sys.argv[2]
244
244
  bundle = {
245
- "schemaVersion": 3, "source": "flow-agents/workflow-sidecar",
245
+ "schemaVersion": 5, "source": "flow-agents/workflow-sidecar",
246
246
  "claims": [{
247
247
  "id": "c1", "subjectId": slug + "/tests", "subjectType": "custom",
248
248
  "claimType": "acme.custom.verify", # neither workflow.* NOR declared by the flow
@@ -263,7 +263,7 @@ bundle = {
263
263
  }
264
264
  json.dump(bundle, open(bundle_path, 'w'))
265
265
  PY
266
- write_fail_log "$T2/.flow-agents/nondeclared/command-log.jsonl"
266
+ write_fail_log "$T2/.kontourai/flow-agents/nondeclared/command-log.jsonl"
267
267
 
268
268
  set +e
269
269
  t2_out="$(FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_BACKSTOP=skip \
@@ -293,9 +293,9 @@ echo "=== 3. NO OVER-BLOCK (a): clean session, no captured fails ==="
293
293
 
294
294
  T3="$TMP/t3-clean"
295
295
  seed_delivered "$T3" "clean-sess"
296
- printf '%s' '{"artifact_dir":"clean-sess"}' > "$T3/.flow-agents/current.json"
297
- write_kit_pass_bundle "$T3/.flow-agents/clean-sess/trust.bundle" "clean-sess"
298
- write_pass_log "$T3/.flow-agents/clean-sess/command-log.jsonl"
296
+ printf '%s' '{"artifact_dir":"clean-sess"}' > "$T3/.kontourai/flow-agents/current.json"
297
+ write_kit_pass_bundle "$T3/.kontourai/flow-agents/clean-sess/trust.bundle" "clean-sess"
298
+ write_pass_log "$T3/.kontourai/flow-agents/clean-sess/command-log.jsonl"
299
299
 
300
300
  set +e
301
301
  t3_out="$(run_gate "$T3")"
@@ -319,13 +319,13 @@ echo "=== 4. NO OVER-BLOCK (b): fail-then-re-run-to-pass (latest capture PASS) =
319
319
 
320
320
  T4="$TMP/t4-rerun"
321
321
  seed_delivered "$T4" "rerun-pass"
322
- printf '%s' '{"artifact_dir":"rerun-pass"}' > "$T4/.flow-agents/current.json"
323
- write_kit_pass_bundle "$T4/.flow-agents/rerun-pass/trust.bundle" "rerun-pass"
322
+ printf '%s' '{"artifact_dir":"rerun-pass"}' > "$T4/.kontourai/flow-agents/current.json"
323
+ write_kit_pass_bundle "$T4/.kontourai/flow-agents/rerun-pass/trust.bundle" "rerun-pass"
324
324
  # FAIL first, then PASS (re-run fixed it — latest is PASS)
325
325
  {
326
326
  printf '%s\n' '{"command":"npm test","observedResult":"fail","exitCode":1,"capturedAt":"2026-06-27T00:00:00Z","source":"test"}'
327
327
  printf '%s\n' '{"command":"npm test","observedResult":"pass","exitCode":0,"capturedAt":"2026-06-27T00:00:01Z","source":"test"}'
328
- } > "$T4/.flow-agents/rerun-pass/command-log.jsonl"
328
+ } > "$T4/.kontourai/flow-agents/rerun-pass/command-log.jsonl"
329
329
 
330
330
  set +e
331
331
  t4_out="$(run_gate "$T4")"
@@ -349,14 +349,14 @@ echo "=== 5. NO OVER-BLOCK (c): acknowledged failure (evidence marks command dis
349
349
 
350
350
  T5="$TMP/t5-ack"
351
351
  seed_delivered "$T5" "ack-fail"
352
- printf '%s' '{"artifact_dir":"ack-fail"}' > "$T5/.flow-agents/current.json"
352
+ printf '%s' '{"artifact_dir":"ack-fail"}' > "$T5/.kontourai/flow-agents/current.json"
353
353
 
354
354
  # Bundle: claim acknowledges failure (status=disputed, value=fail)
355
- python3 - "$T5/.flow-agents/ack-fail/trust.bundle" "ack-fail" << 'PY'
355
+ python3 - "$T5/.kontourai/flow-agents/ack-fail/trust.bundle" "ack-fail" << 'PY'
356
356
  import json, sys
357
357
  bundle_path, slug = sys.argv[1], sys.argv[2]
358
358
  bundle = {
359
- "schemaVersion": 3, "source": "flow-agents/workflow-sidecar",
359
+ "schemaVersion": 5, "source": "flow-agents/workflow-sidecar",
360
360
  "claims": [{
361
361
  "id": "c1", "subjectId": slug + "/tests", "subjectType": "flow-step",
362
362
  "claimType": "builder.verify.tests",
@@ -379,7 +379,7 @@ bundle = {
379
379
  }
380
380
  json.dump(bundle, open(bundle_path, 'w'))
381
381
  PY
382
- write_fail_log "$T5/.flow-agents/ack-fail/command-log.jsonl"
382
+ write_fail_log "$T5/.kontourai/flow-agents/ack-fail/command-log.jsonl"
383
383
 
384
384
  set +e
385
385
  t5_out="$(run_gate "$T5")"
@@ -403,12 +403,12 @@ echo "=== 6. NO OVER-BLOCK (d): no-command doc/policy session (verified, no exec
403
403
  echo " (#216 fix: missing-log check must NOT fire when no command was expected)"
404
404
 
405
405
  T6="$TMP/t6-nocommand"
406
- mkdir -p "$T6/.flow-agents/nocommand"
406
+ mkdir -p "$T6/.kontourai/flow-agents/nocommand"
407
407
  printf '# Repo\n' > "$T6/AGENTS.md"
408
408
  # State is verified (completing) but no commands were run
409
409
  printf '%s' '{"schema_version":"1.0","task_slug":"nocommand","status":"verified","phase":"verification","updated_at":"2026-06-27T00:00:00Z","next_action":{"status":"done","summary":"done"}}' \
410
- > "$T6/.flow-agents/nocommand/state.json"
411
- cat > "$T6/.flow-agents/nocommand/nocommand--deliver.md" << 'MD'
410
+ > "$T6/.kontourai/flow-agents/nocommand/state.json"
411
+ cat > "$T6/.kontourai/flow-agents/nocommand/nocommand--deliver.md" << 'MD'
412
412
  # nocommand
413
413
 
414
414
  branch: main
@@ -423,13 +423,13 @@ type: deliver
423
423
 
424
424
  ### Verdict: PASS
425
425
  MD
426
- printf '%s' '{"artifact_dir":"nocommand"}' > "$T6/.flow-agents/current.json"
426
+ printf '%s' '{"artifact_dir":"nocommand"}' > "$T6/.kontourai/flow-agents/current.json"
427
427
 
428
428
  # Bundle with NO execution.label (doc/policy session — no commands run)
429
- python3 - "$T6/.flow-agents/nocommand/trust.bundle" << 'PY'
429
+ python3 - "$T6/.kontourai/flow-agents/nocommand/trust.bundle" << 'PY'
430
430
  import json, sys
431
431
  bundle = {
432
- "schemaVersion": 3, "source": "flow-agents/workflow-sidecar",
432
+ "schemaVersion": 5, "source": "flow-agents/workflow-sidecar",
433
433
  "claims": [{
434
434
  "id": "c1", "subjectId": "nocommand/review", "subjectType": "workflow-check",
435
435
  "claimType": "workflow.check.review", "fieldOrBehavior": "policy doc reviewed",
@@ -476,11 +476,11 @@ echo " (Two-part dependency: union form ALWAYS enforces workflow.* + empty-ex
476
476
  echo " emits gate-misconfiguration HARD_BLOCK for empty expects[])"
477
477
 
478
478
  T7="$TMP/t7-empty-expects"
479
- mkdir -p "$T7/.flow-agents/empty-expects"
479
+ mkdir -p "$T7/.kontourai/flow-agents/empty-expects"
480
480
  printf '# Repo\n' > "$T7/AGENTS.md"
481
481
  printf '%s' '{"schema_version":"1.0","task_slug":"empty-expects","status":"in_progress","phase":"execution","updated_at":"2026-06-27T00:00:00Z","next_action":{"status":"in_progress","summary":"Testing"}}' \
482
- > "$T7/.flow-agents/empty-expects/state.json"
483
- cat > "$T7/.flow-agents/empty-expects/empty-expects--deliver.md" << 'MD'
482
+ > "$T7/.kontourai/flow-agents/empty-expects/state.json"
483
+ cat > "$T7/.kontourai/flow-agents/empty-expects/empty-expects--deliver.md" << 'MD'
484
484
  # empty-expects
485
485
 
486
486
  branch: main
@@ -491,14 +491,14 @@ type: deliver
491
491
  - [ ] tests pass
492
492
  MD
493
493
  printf '%s' '{"artifact_dir":"empty-expects","active_flow_id":"builder.build","active_step_id":"verify"}' \
494
- > "$T7/.flow-agents/current.json"
494
+ > "$T7/.kontourai/flow-agents/current.json"
495
495
 
496
496
  # Bundle with ONLY kit-typed claims (no workflow.*)
497
- python3 - "$T7/.flow-agents/empty-expects/trust.bundle" "empty-expects" << 'PY'
497
+ python3 - "$T7/.kontourai/flow-agents/empty-expects/trust.bundle" "empty-expects" << 'PY'
498
498
  import json, sys
499
499
  bundle_path, slug = sys.argv[1], sys.argv[2]
500
500
  bundle = {
501
- "schemaVersion": 3, "source": "flow-agents/workflow-sidecar",
501
+ "schemaVersion": 5, "source": "flow-agents/workflow-sidecar",
502
502
  "claims": [{
503
503
  "id": "c1", "subjectId": slug + "/tests", "subjectType": "flow-step",
504
504
  "claimType": "builder.verify.tests",
@@ -510,7 +510,7 @@ bundle = {
510
510
  }
511
511
  json.dump(bundle, open(bundle_path, 'w'))
512
512
  PY
513
- printf '' > "$T7/.flow-agents/empty-expects/command-log.jsonl"
513
+ printf '' > "$T7/.kontourai/flow-agents/empty-expects/command-log.jsonl"
514
514
 
515
515
  # Fake flow with expects:[] (safe dir, not agent-writable)
516
516
  FAKE_FLOWS="$TMP/fake-flows-ac3"
@@ -566,12 +566,12 @@ echo " PRE-FIX: completing guard skipped reconciliation for non-terminal stat
566
566
  echo " POST-FIX: guard removed → check runs on every stop (status-independent)"
567
567
 
568
568
  T8="$TMP/t8-status-dodge"
569
- mkdir -p "$T8/.flow-agents/status-dodge"
569
+ mkdir -p "$T8/.kontourai/flow-agents/status-dodge"
570
570
  printf '# Repo\n' > "$T8/AGENTS.md"
571
571
  # CRITICAL: status = 'blocked' (non-terminal — pre-fix would have returned [] here)
572
572
  printf '%s' '{"schema_version":"1.0","task_slug":"status-dodge","status":"blocked","phase":"executing","updated_at":"2026-06-27T00:00:00Z","next_action":{"status":"in_progress","summary":"running"}}' \
573
- > "$T8/.flow-agents/status-dodge/state.json"
574
- cat > "$T8/.flow-agents/status-dodge/status-dodge--deliver.md" << 'MD'
573
+ > "$T8/.kontourai/flow-agents/status-dodge/state.json"
574
+ cat > "$T8/.kontourai/flow-agents/status-dodge/status-dodge--deliver.md" << 'MD'
575
575
  # status-dodge
576
576
 
577
577
  branch: main
@@ -588,11 +588,11 @@ type: deliver
588
588
  MD
589
589
 
590
590
  # Bundle: kit-typed claim asserting pass for "npm test"
591
- python3 - "$T8/.flow-agents/status-dodge/trust.bundle" "status-dodge" << 'PY'
591
+ python3 - "$T8/.kontourai/flow-agents/status-dodge/trust.bundle" "status-dodge" << 'PY'
592
592
  import json, sys
593
593
  bundle_path, slug = sys.argv[1], sys.argv[2]
594
594
  bundle = {
595
- "schemaVersion": 3, "source": "flow-agents/workflow-sidecar",
595
+ "schemaVersion": 5, "source": "flow-agents/workflow-sidecar",
596
596
  "claims": [{
597
597
  "id": "c1", "subjectId": slug + "/tests", "subjectType": "flow-step",
598
598
  "claimType": "builder.verify.tests",
@@ -614,7 +614,7 @@ bundle = {
614
614
  json.dump(bundle, open(bundle_path, 'w'))
615
615
  PY
616
616
  # command-log: "npm test" FAIL (latest capture is FAIL — the agent lied)
617
- write_fail_log "$T8/.flow-agents/status-dodge/command-log.jsonl"
617
+ write_fail_log "$T8/.kontourai/flow-agents/status-dodge/command-log.jsonl"
618
618
 
619
619
  echo ""
620
620
  echo "--- 8a. PRE-FIX simulation (completing guard) ---"
@@ -663,14 +663,14 @@ echo " POST-FIX: Case B removed → incidental fails with no claim NOT blocke
663
663
 
664
664
  T9="$TMP/t9-overblock"
665
665
  seed_delivered "$T9" "overblock-sess"
666
- printf '%s' '{"artifact_dir":"overblock-sess"}' > "$T9/.flow-agents/current.json"
666
+ printf '%s' '{"artifact_dir":"overblock-sess"}' > "$T9/.kontourai/flow-agents/current.json"
667
667
  # Bundle: only "npm test" claim asserting pass (no claim about the grep incidental fail)
668
- write_kit_pass_bundle "$T9/.flow-agents/overblock-sess/trust.bundle" "overblock-sess"
668
+ write_kit_pass_bundle "$T9/.kontourai/flow-agents/overblock-sess/trust.bundle" "overblock-sess"
669
669
  # Log: "npm test" PASS + incidental "grep --quiet somepattern AGENTS.md" FAIL (exit 1)
670
670
  printf '%s\n%s\n' \
671
671
  '{"command":"npm test","observedResult":"pass","exitCode":0,"capturedAt":"2026-06-27T00:00:00Z","source":"postToolUse-capture"}' \
672
672
  '{"command":"grep --quiet somepattern AGENTS.md","observedResult":"fail","exitCode":1,"capturedAt":"2026-06-27T00:00:01Z","source":"postToolUse-capture"}' \
673
- > "$T9/.flow-agents/overblock-sess/command-log.jsonl"
673
+ > "$T9/.kontourai/flow-agents/overblock-sess/command-log.jsonl"
674
674
 
675
675
  set +e
676
676
  t9_out="$(run_gate "$T9")"
@@ -708,13 +708,13 @@ echo " POST-FIX: latest-wins → re-run to PASS clears the block"
708
708
 
709
709
  T10="$TMP/t10-fixpass"
710
710
  seed_delivered "$T10" "fixpass-sess"
711
- printf '%s' '{"artifact_dir":"fixpass-sess"}' > "$T10/.flow-agents/current.json"
712
- write_kit_pass_bundle "$T10/.flow-agents/fixpass-sess/trust.bundle" "fixpass-sess"
711
+ printf '%s' '{"artifact_dir":"fixpass-sess"}' > "$T10/.kontourai/flow-agents/current.json"
712
+ write_kit_pass_bundle "$T10/.kontourai/flow-agents/fixpass-sess/trust.bundle" "fixpass-sess"
713
713
  # Log: FAIL first, then PASS (genuine fix-then-re-run)
714
714
  printf '%s\n%s\n' \
715
715
  '{"command":"npm test","observedResult":"fail","exitCode":1,"capturedAt":"2026-06-27T00:00:00Z","source":"postToolUse-capture"}' \
716
716
  '{"command":"npm test","observedResult":"pass","exitCode":0,"capturedAt":"2026-06-27T00:00:01Z","source":"postToolUse-capture"}' \
717
- > "$T10/.flow-agents/fixpass-sess/command-log.jsonl"
717
+ > "$T10/.kontourai/flow-agents/fixpass-sess/command-log.jsonl"
718
718
 
719
719
  set +e
720
720
  t10_out="$(run_gate "$T10")"
@@ -747,13 +747,13 @@ echo " POST-FIX: hasLaunderingOperator detects || true → 'exit-code-launder
747
747
 
748
748
  T11="$TMP/t11-laundering"
749
749
  seed_delivered "$T11" "laundering-sess"
750
- printf '%s' '{"artifact_dir":"laundering-sess"}' > "$T11/.flow-agents/current.json"
750
+ printf '%s' '{"artifact_dir":"laundering-sess"}' > "$T11/.kontourai/flow-agents/current.json"
751
751
  # Bundle: claim asserting pass for "npm test || true" — command string has laundering operator
752
- python3 - "$T11/.flow-agents/laundering-sess/trust.bundle" "laundering-sess" << 'PY'
752
+ python3 - "$T11/.kontourai/flow-agents/laundering-sess/trust.bundle" "laundering-sess" << 'PY'
753
753
  import json, sys
754
754
  bundle_path, slug = sys.argv[1], sys.argv[2]
755
755
  bundle = {
756
- "schemaVersion": 3, "source": "flow-agents/workflow-sidecar",
756
+ "schemaVersion": 5, "source": "flow-agents/workflow-sidecar",
757
757
  "claims": [{
758
758
  "id": "c1", "subjectId": slug + "/tests", "subjectType": "flow-step",
759
759
  "claimType": "builder.verify.tests",
@@ -777,7 +777,7 @@ PY
777
777
  # Log: "npm test || true" captured as PASS (exit 0) — the laundering worked
778
778
  printf '%s\n' \
779
779
  '{"command":"npm test || true","observedResult":"pass","exitCode":0,"capturedAt":"2026-06-27T00:00:00Z","source":"postToolUse-capture"}' \
780
- > "$T11/.flow-agents/laundering-sess/command-log.jsonl"
780
+ > "$T11/.kontourai/flow-agents/laundering-sess/command-log.jsonl"
781
781
 
782
782
  set +e
783
783
  t11_out="$(run_gate "$T11")"
@@ -15,6 +15,10 @@
15
15
  # This proves the signing PATH is structurally correct without needing real OIDC.
16
16
  # 4. ADDITIVE: all existing gating tests still pass (record-release, advance-state-delivered,
17
17
  # seal-checkpoint, record-evidence, record-critique all unaffected).
18
+ # 5. NO-CLOBBER (WS5 iteration-2 part 2 regression guard): this eval's scratch sessions
19
+ # (mktemp -d, no kits/ ancestor) never publish into this real repo's delivery/trust.bundle,
20
+ # even when the eval is run from a checkout of this repo — publish-delivery's repo-root
21
+ # resolution is fail-closed and TEST 2 passes an explicit scratch --repo-root.
18
22
  #
19
23
  # Deterministic, no model spend, no network, self-cleaning.
20
24
  # Usage: bash evals/integration/test_checkpoint_signing.sh
@@ -34,6 +38,19 @@ _fail() { echo " ✗ $1"; errors=$((errors + 1)); }
34
38
  cleanup() { rm -rf "$TMP"; }
35
39
  trap cleanup EXIT
36
40
 
41
+ # REGRESSION GUARD (WS5 iteration-2 part 2): this eval's scratch sessions live under a
42
+ # mktemp -d tree with no kits/ ancestor. Before the fail-closed fix to
43
+ # findRepoRootFromDir/publishDelivery in src/cli/workflow-sidecar.ts, a scratch session's
44
+ # record-release / advance-state --status delivered call would silently fall back to
45
+ # process.cwd() for its delivery/ repo-root — and when this eval runs from a checkout of
46
+ # THIS repo (as it does under npm run eval:static / the integration suite), that clobbered
47
+ # the real repo's own delivery/trust.bundle with scratch fixture content. Capture this real
48
+ # repo's delivery/trust.bundle content hash now (before any scratch session in this eval
49
+ # runs) and re-check it is byte-identical after every test below.
50
+ REAL_DELIVERY_BUNDLE="$ROOT/delivery/trust.bundle"
51
+ _bundle_hash() { if [[ -f "$1" ]]; then shasum -a 256 "$1" | awk '{print $1}'; else echo "absent"; fi; }
52
+ REAL_DELIVERY_HASH_BEFORE="$(_bundle_hash "$REAL_DELIVERY_BUNDLE")"
53
+
37
54
  # ─────────────────────────────────────────────────────────────────────────────
38
55
  echo ""
39
56
  echo "=== TEST 1: Statement produced with correct subject (sha256 of checkpoint) ==="
@@ -242,6 +259,14 @@ SLUG2="sign-test-failopen"
242
259
  SESSION_DIR2="$AROOT2/$SLUG2"
243
260
  mkdir -p "$AROOT2"
244
261
 
262
+ # REGRESSION FIX (WS5 iteration-2 part 2): this session dir has no kits/ ancestor of its
263
+ # own (it lives under $TMP). Pass an explicit --repo-root pointing at a scratch repo-root
264
+ # under $TMP so advance-state --status delivered's auto-publish never has to fall back to
265
+ # (or, pre-fix, silently trust) process.cwd() — matching test_publish_delivery.sh's pattern
266
+ # of always giving its scratch sessions an explicit repo-root.
267
+ REPO_ROOT2="$TMP/test2/scratch-repo"
268
+ mkdir -p "$REPO_ROOT2"
269
+
245
270
  flow_agents_node "$WRITER" ensure-session \
246
271
  --artifact-root "$AROOT2" \
247
272
  --task-slug "$SLUG2" \
@@ -264,6 +289,7 @@ flow_agents_node "$WRITER" advance-state "$SESSION_DIR2" \
264
289
  --status delivered \
265
290
  --phase release \
266
291
  --summary "Delivered." \
292
+ --repo-root "$REPO_ROOT2" \
267
293
  --timestamp "2026-06-26T11:03:00Z" >/dev/null 2>&1 || SEAL_EXIT=$?
268
294
 
269
295
  if [[ "$SEAL_EXIT" -eq 0 ]]; then
@@ -272,6 +298,12 @@ else
272
298
  _fail "advance-state --status delivered exited $SEAL_EXIT (signing must not break the seal)"
273
299
  fi
274
300
 
301
+ if [[ -f "$REPO_ROOT2/delivery/trust.bundle" ]]; then
302
+ _pass "publish-delivery published into the explicit scratch --repo-root ($REPO_ROOT2/delivery/trust.bundle), not process.cwd()"
303
+ else
304
+ _fail "publish-delivery did not write to the explicit scratch --repo-root ($REPO_ROOT2/delivery/trust.bundle) — check the --repo-root plumbing in advanceState"
305
+ fi
306
+
275
307
  if [[ -f "$SESSION_DIR2/trust.checkpoint.json" ]]; then
276
308
  _pass "trust.checkpoint.json written even when signing is fail-open"
277
309
  else
@@ -477,6 +509,17 @@ else
477
509
  _fail "Increment A checkpoint envelope shape broken (regression)"
478
510
  fi
479
511
 
512
+ # ─────────────────────────────────────────────────────────────────────────────
513
+ echo ""
514
+ echo "=== TEST 5: Regression — this eval's scratch sessions never touch the real repo's delivery/trust.bundle ==="
515
+
516
+ REAL_DELIVERY_HASH_AFTER="$(_bundle_hash "$REAL_DELIVERY_BUNDLE")"
517
+ if [[ "$REAL_DELIVERY_HASH_AFTER" == "$REAL_DELIVERY_HASH_BEFORE" ]]; then
518
+ _pass "real repo delivery/trust.bundle unchanged by this eval's scratch sessions (before=$REAL_DELIVERY_HASH_BEFORE after=$REAL_DELIVERY_HASH_AFTER)"
519
+ else
520
+ _fail "real repo delivery/trust.bundle CHANGED during this eval (before=$REAL_DELIVERY_HASH_BEFORE after=$REAL_DELIVERY_HASH_AFTER) — a scratch session's publish-delivery clobbered $REAL_DELIVERY_BUNDLE"
521
+ fi
522
+
480
523
  # ─────────────────────────────────────────────────────────────────────────────
481
524
  echo ""
482
525
  echo "────────────────────────────────────────────"
@@ -46,14 +46,14 @@ seed_disputed_bundle() {
46
46
  mkdir -p "$dir"
47
47
  cat > "$dir/trust.bundle" <<JSON
48
48
  {
49
- "schemaVersion": 3,
49
+ "schemaVersion": 5,
50
50
  "source": "claim-lookup-test;statusFunctionVersion=1",
51
51
  "claims": [
52
52
  {
53
53
  "id": "$claimId",
54
54
  "subjectType": "workflow-check",
55
55
  "subjectId": "${slug}/unit-tests",
56
- "surface": "flow-agents.workflow",
56
+ "facet": "flow-agents.workflow",
57
57
  "claimType": "workflow.check.test",
58
58
  "fieldOrBehavior": "unit tests pass",
59
59
  "value": "fail",
@@ -255,14 +255,14 @@ mkdir -p "$AC5_DIR"
255
255
  # won't match any evidence check id and bundleEnforcement won't be deduped.
256
256
  cat > "$AC5_DIR/trust.bundle" <<'BUNDLE'
257
257
  {
258
- "schemaVersion": 3,
258
+ "schemaVersion": 5,
259
259
  "source": "claim-lookup-test",
260
260
  "claims": [
261
261
  {
262
262
  "id": "gate-hint-test/AC1.flow-agents.workflow.acceptance criterion verified",
263
263
  "subjectType": "workflow-criterion",
264
264
  "subjectId": "gate-hint-test/AC1",
265
- "surface": "flow-agents.workflow",
265
+ "facet": "flow-agents.workflow",
266
266
  "claimType": "workflow.acceptance.criterion",
267
267
  "fieldOrBehavior": "acceptance criterion verified",
268
268
  "value": "fail",
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env bash
2
+ # test_codex_hook_resolution.sh - exercises the literal hooks.json command
3
+ # strings emitted by build-universal-bundles.ts against the CODEX_HOME
4
+ # resolution edge cases that a live Codex session actually hits: CODEX_HOME
5
+ # unset/stale, and cwd being an unrelated project rather than this repo.
6
+ #
7
+ # Coverage gap this closes: test_codex_harness.sh only runs when a `codex`
8
+ # binary is on PATH (it skips-as-pass otherwise, and no CI workflow installs
9
+ # one), and every other hook eval calls the underlying script directly
10
+ # (e.g. `node scripts/hooks/stop-goal-fit.js`), bypassing the bash -lc
11
+ # CODEX_HOME resolver in hooks.json entirely. Neither ever caught a resolver
12
+ # bug, which is exactly what shipped: every hook exited 1 in real usage
13
+ # whenever CODEX_HOME wasn't exported into the hook's process and the
14
+ # project cwd didn't happen to vendor scripts/hooks itself.
15
+ set -uo pipefail
16
+
17
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
18
+ source "$ROOT/evals/lib/node.sh"
19
+
20
+ errors=0
21
+ TMPDIR_EVAL="$(mktemp -d)"
22
+ trap 'rm -rf "$TMPDIR_EVAL"' EXIT
23
+
24
+ _pass() { echo " ✓ $1"; }
25
+ _fail() { echo " ✗ $1"; errors=$((errors + 1)); }
26
+
27
+ echo "=== Codex Hook Resolution ==="
28
+ echo ""
29
+
30
+ if flow_agents_node scripts/build-universal-bundles.js >/dev/null; then
31
+ _pass "bundle build completed"
32
+ else
33
+ _fail "bundle build failed"
34
+ fi
35
+
36
+ HOOKS_JSON="$ROOT/dist/codex/.codex/hooks.json"
37
+ if [[ -f "$HOOKS_JSON" ]]; then
38
+ _pass "dist/codex/.codex/hooks.json exists"
39
+ else
40
+ _fail "dist/codex/.codex/hooks.json missing"
41
+ fi
42
+
43
+ # Pull the exact SessionStart workflow-steering command string Codex would run.
44
+ SESSION_START_CMD="$(node -e '
45
+ const hooks = require(process.argv[1]).hooks.SessionStart;
46
+ const entry = hooks.find(group => group.hooks[0].command.includes("codex-hook-adapter.js"));
47
+ process.stdout.write(entry.hooks[0].command);
48
+ ' "$HOOKS_JSON")"
49
+
50
+ if [[ "$SESSION_START_CMD" == *"codex-hook-adapter.js"* ]]; then
51
+ _pass "extracted SessionStart hook command"
52
+ else
53
+ _fail "could not extract SessionStart hook command"
54
+ fi
55
+
56
+ # An unrelated project: a real git repo that does NOT vendor scripts/hooks,
57
+ # which is what every real installation target looks like (this repo is the
58
+ # one exception, since it dogfoods itself from its own repo root).
59
+ PROJECT="$TMPDIR_EVAL/unrelated-project"
60
+ mkdir -p "$PROJECT"
61
+ git init -q "$PROJECT"
62
+
63
+ HOME_WITH_INSTALL="$TMPDIR_EVAL/home-with-install"
64
+ mkdir -p "$HOME_WITH_INSTALL"
65
+ bash "$ROOT/dist/codex/install.sh" "$HOME_WITH_INSTALL/.codex" >/dev/null
66
+
67
+ HOME_EMPTY="$TMPDIR_EVAL/home-empty"
68
+ mkdir -p "$HOME_EMPTY"
69
+
70
+ echo ""
71
+ echo "--- CODEX_HOME set correctly (baseline) ---"
72
+ OUT="$(cd "$PROJECT" && CODEX_HOME="$HOME_WITH_INSTALL/.codex" bash -lc "$SESSION_START_CMD" <<<'{"hook_event_name":"SessionStart"}' 2>"$TMPDIR_EVAL/stderr.baseline")"
73
+ STATUS=$?
74
+ if [[ $STATUS -eq 0 ]] && [[ "$OUT" == *'"continue":true'* ]]; then
75
+ _pass "hook succeeds when CODEX_HOME is set and correct"
76
+ else
77
+ _fail "hook should succeed when CODEX_HOME is set and correct (exit $STATUS): $OUT"
78
+ fi
79
+
80
+ echo ""
81
+ echo "--- CODEX_HOME unset, unrelated cwd, install lives under \$HOME/.codex ---"
82
+ OUT="$(cd "$PROJECT" && unset CODEX_HOME && HOME="$HOME_WITH_INSTALL" bash -lc "$SESSION_START_CMD" <<<'{"hook_event_name":"SessionStart"}' 2>"$TMPDIR_EVAL/stderr.fallback")"
83
+ STATUS=$?
84
+ if [[ $STATUS -eq 0 ]] && [[ "$OUT" == *'"continue":true'* ]]; then
85
+ _pass "hook falls back to \$HOME/.codex and succeeds when CODEX_HOME is unset"
86
+ else
87
+ _fail "hook should fall back to \$HOME/.codex when CODEX_HOME is unset (exit $STATUS): $OUT"
88
+ fi
89
+
90
+ echo ""
91
+ echo "--- CODEX_HOME unset, unrelated cwd, no install anywhere (fail open) ---"
92
+ set +e
93
+ OUT="$(cd "$PROJECT" && unset CODEX_HOME && HOME="$HOME_EMPTY" bash -lc "$SESSION_START_CMD" <<<'{"hook_event_name":"SessionStart"}' 2>"$TMPDIR_EVAL/stderr.missing")"
94
+ STATUS=$?
95
+ set -e
96
+ if [[ $STATUS -eq 0 ]]; then
97
+ _pass "hook exits 0 (fails open) instead of crashing when the script cannot be found anywhere"
98
+ else
99
+ _fail "hook should fail open with exit 0 when unresolvable, got exit $STATUS"
100
+ fi
101
+
102
+ if grep -q "hook script not found" "$TMPDIR_EVAL/stderr.missing"; then
103
+ _pass "hook reports a clear diagnostic instead of a bare module-not-found crash"
104
+ else
105
+ _fail "hook did not report a diagnostic when the script was unresolvable"
106
+ fi
107
+
108
+ echo ""
109
+ if [[ $errors -gt 0 ]]; then
110
+ echo "FAILED: $errors error(s)"
111
+ exit 1
112
+ fi
113
+ echo "PASSED"
114
+ exit 0
@@ -30,15 +30,15 @@ trap cleanup EXIT
30
30
 
31
31
  REPO="$TMP/repo"
32
32
  SLUG="conc"
33
- mkdir -p "$REPO/.flow-agents/$SLUG"
33
+ mkdir -p "$REPO/.kontourai/flow-agents/$SLUG"
34
34
  printf '# Repo\n' > "$REPO/AGENTS.md"
35
35
  # Anchor the capture log to this slug. evidence-capture.js resolves the artifact
36
- # dir via .flow-agents/current.json (active_slug) or the newest state.json; seed
37
- # both so resolveArtifactDir() points at .flow-agents/<slug>/.
38
- printf '{"active_slug":"%s","artifact_dir":".flow-agents/%s"}' "$SLUG" "$SLUG" \
39
- > "$REPO/.flow-agents/current.json"
36
+ # dir via .kontourai/flow-agents/current.json (active_slug) or the newest state.json; seed
37
+ # both so resolveArtifactDir() points at .kontourai/flow-agents/<slug>/.
38
+ printf '{"active_slug":"%s","artifact_dir":".kontourai/flow-agents/%s"}' "$SLUG" "$SLUG" \
39
+ > "$REPO/.kontourai/flow-agents/current.json"
40
40
  printf '%s' "{\"schema_version\":\"1.0\",\"task_slug\":\"$SLUG\",\"status\":\"in_progress\",\"phase\":\"build\",\"updated_at\":\"2026-06-23T00:00:00Z\",\"next_action\":{\"status\":\"in_progress\",\"summary\":\"work\"}}" \
41
- > "$REPO/.flow-agents/$SLUG/state.json"
41
+ > "$REPO/.kontourai/flow-agents/$SLUG/state.json"
42
42
 
43
43
  N=24
44
44
  echo "Test: $N concurrent captures into one command-log must not fork the chain"
@@ -51,7 +51,7 @@ for i in $(seq 1 "$N"); do
51
51
  done
52
52
  wait
53
53
 
54
- LOG="$REPO/.flow-agents/$SLUG/command-log.jsonl"
54
+ LOG="$REPO/.kontourai/flow-agents/$SLUG/command-log.jsonl"
55
55
 
56
56
  # 1. All N records present.
57
57
  count=$(grep -c '' "$LOG" 2>/dev/null || echo 0)
@@ -91,7 +91,7 @@ else
91
91
  fi
92
92
 
93
93
  # 3. The verifier confirms an intact chain.
94
- chain_status=$(node -e "const g = require('$GATE'); console.log(g.verifyCommandLogChain('$REPO/.flow-agents/$SLUG').status);")
94
+ chain_status=$(node -e "const g = require('$GATE'); console.log(g.verifyCommandLogChain('$REPO/.kontourai/flow-agents/$SLUG').status);")
95
95
  if [[ "$chain_status" == "ok" ]]; then
96
96
  _pass "verifyCommandLogChain → ok under concurrency"
97
97
  else
@@ -22,7 +22,7 @@ errors=0
22
22
  _pass() { echo " ✓ $1"; }
23
23
  _fail() { echo " ✗ $1"; errors=$((errors + 1)); }
24
24
 
25
- SD=".flow-agents/s"
25
+ SD=".kontourai/flow-agents/s"
26
26
 
27
27
  # Build a command-log from a spec: JSON array of {cmd,exit,src,parent} where
28
28
  # parent is the 0-based index of the entry whose hash is this entry's prevHash
@@ -41,10 +41,10 @@ build() { # $1=dir $2=spec-json
41
41
  const prev=s.parent===-1?GEN:hashes[s.parent]; const h=H(prev,rec);
42
42
  hashes.push(h); lines.push(JSON.stringify({...rec,_chain:{seq:i,prevHash:prev,hash:h}}));
43
43
  });
44
- fs.writeFileSync(path.join(process.env.DIR,".flow-agents/s/command-log.jsonl"),lines.join("\n")+"\n");
44
+ fs.writeFileSync(path.join(process.env.DIR,".kontourai/flow-agents/s/command-log.jsonl"),lines.join("\n")+"\n");
45
45
  ' "$2"
46
46
  }
47
- status() { DIR="$1" node -e 'const g=require(process.env.GATE);console.log(g.verifyCommandLogChain(process.env.DIR+"/.flow-agents/s").status)' ; }
47
+ status() { DIR="$1" node -e 'const g=require(process.env.GATE);console.log(g.verifyCommandLogChain(process.env.DIR+"/.kontourai/flow-agents/s").status)' ; }
48
48
 
49
49
  # ── 1. linear → ok ────────────────────────────────────────────────────────────
50
50
  D="$TMP/linear"; build "$D" '[{"cmd":"a","exit":0,"parent":-1},{"cmd":"b","exit":0,"parent":0}]'