@kontourai/flow-agents 2.2.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 +46 -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
@@ -9,7 +9,7 @@
9
9
  #
10
10
  # Covers:
11
11
  # AC1 — config-protection.js: blocked Write/Edit to kill-switch / routing files
12
- # (.claude/settings.json, shell profiles, .flow-agents/current.json) and
12
+ # (.claude/settings.json, shell profiles, .kontourai/flow-agents/current.json) and
13
13
  # shell-redirect detection (best-effort, incomplete coverage).
14
14
  # AC2 — stop-goal-fit.js: MAX_BLOCKS cannot release a HARD block (false-completion
15
15
  # / integrity failure); only soft/advisory streaks may auto-release.
@@ -40,11 +40,11 @@ trap cleanup EXIT
40
40
 
41
41
  seed_repo_inprogress() { # $1=dir $2=slug $3=phase(opt) $4=status(opt)
42
42
  local dir="$1" slug="$2" phase="${3:-execution}" status="${4:-in_progress}"
43
- mkdir -p "$dir/.flow-agents/$slug"
43
+ mkdir -p "$dir/.kontourai/flow-agents/$slug"
44
44
  printf '# Repo\n' > "$dir/AGENTS.md"
45
45
  printf '%s' "{\"schema_version\":\"1.0\",\"task_slug\":\"$slug\",\"status\":\"$status\",\"phase\":\"$phase\",\"updated_at\":\"2026-06-27T00:00:00Z\",\"next_action\":{\"status\":\"in_progress\",\"summary\":\"Testing\"}}" \
46
- > "$dir/.flow-agents/$slug/state.json"
47
- cat > "$dir/.flow-agents/$slug/$slug--deliver.md" << MD
46
+ > "$dir/.kontourai/flow-agents/$slug/state.json"
47
+ cat > "$dir/.kontourai/flow-agents/$slug/$slug--deliver.md" << MD
48
48
  # $slug
49
49
 
50
50
  branch: main
@@ -58,11 +58,11 @@ MD
58
58
 
59
59
  seed_repo_preexec() { # $1=dir $2=slug
60
60
  local dir="$1" slug="$2"
61
- mkdir -p "$dir/.flow-agents/$slug"
61
+ mkdir -p "$dir/.kontourai/flow-agents/$slug"
62
62
  printf '# Repo\n' > "$dir/AGENTS.md"
63
63
  printf '%s' "{\"schema_version\":\"1.0\",\"task_slug\":\"$slug\",\"status\":\"planned\",\"phase\":\"planning\",\"updated_at\":\"2026-06-27T00:00:00Z\",\"next_action\":{\"status\":\"planned\",\"summary\":\"Planning\"}}" \
64
- > "$dir/.flow-agents/$slug/state.json"
65
- cat > "$dir/.flow-agents/$slug/$slug--deliver.md" << MD
64
+ > "$dir/.kontourai/flow-agents/$slug/state.json"
65
+ cat > "$dir/.kontourai/flow-agents/$slug/$slug--deliver.md" << MD
66
66
  # $slug
67
67
 
68
68
  branch: main
@@ -78,7 +78,7 @@ write_clean_bundle() { # $1=path
78
78
  python3 - "$1" << 'PY'
79
79
  import json, sys
80
80
  bundle = {
81
- "schemaVersion": 3, "source": "test",
81
+ "schemaVersion": 5, "source": "test",
82
82
  "claims": [], "evidence": [], "policies": [], "events": []
83
83
  }
84
84
  json.dump(bundle, open(sys.argv[1], 'w'))
@@ -90,7 +90,7 @@ write_high_impact_bundle() { # $1=path $2=slug $3=status(verified|disputed)
90
90
  import json, sys
91
91
  bp, slug, status = sys.argv[1], sys.argv[2], sys.argv[3]
92
92
  bundle = {
93
- "schemaVersion": 3, "source": "test",
93
+ "schemaVersion": 5, "source": "test",
94
94
  "claims": [{
95
95
  "id": "c-high",
96
96
  "subjectId": slug + "/tests",
@@ -189,15 +189,15 @@ for profile in ".bash_profile" ".bashrc" ".profile" ".zprofile" ".zshrc"; do
189
189
  done
190
190
 
191
191
  echo ""
192
- echo "--- AC1.3: Write/Edit to .flow-agents/current.json BLOCKED ---"
192
+ echo "--- AC1.3: Write/Edit to .kontourai/flow-agents/current.json BLOCKED ---"
193
193
  set +e
194
- prot_out=$(echo '{"tool_name":"Write","tool_input":{"path":"/repo/.flow-agents/current.json"}}' | node "$PROT" 2>&1)
194
+ prot_out=$(echo '{"tool_name":"Write","tool_input":{"path":"/repo/.kontourai/flow-agents/current.json"}}' | node "$PROT" 2>&1)
195
195
  prot_exit=$?
196
196
  set -e
197
197
  if [ "$prot_exit" -eq 2 ] && echo "$prot_out" | grep -q "BLOCKED"; then
198
- _pass "Write to .flow-agents/current.json blocked (exit 2)"
198
+ _pass "Write to .kontourai/flow-agents/current.json blocked (exit 2)"
199
199
  else
200
- _fail "Write to .flow-agents/current.json NOT blocked (exit=$prot_exit)"
200
+ _fail "Write to .kontourai/flow-agents/current.json NOT blocked (exit=$prot_exit)"
201
201
  fi
202
202
 
203
203
  echo ""
@@ -238,15 +238,15 @@ else
238
238
  fi
239
239
 
240
240
  echo ""
241
- echo "--- AC1.7: tee .flow-agents/current.json BLOCKED ---"
241
+ echo "--- AC1.7: tee .kontourai/flow-agents/current.json BLOCKED ---"
242
242
  set +e
243
- prot_out=$(echo '{"tool_name":"Bash","tool_input":{"command":"echo {} | tee .flow-agents/current.json"}}' | node "$PROT" 2>&1)
243
+ prot_out=$(echo '{"tool_name":"Bash","tool_input":{"command":"echo {} | tee .kontourai/flow-agents/current.json"}}' | node "$PROT" 2>&1)
244
244
  prot_exit=$?
245
245
  set -e
246
246
  if [ "$prot_exit" -eq 2 ]; then
247
- _pass "tee to .flow-agents/current.json blocked (exit 2)"
247
+ _pass "tee to .kontourai/flow-agents/current.json blocked (exit 2)"
248
248
  else
249
- _fail "tee to .flow-agents/current.json NOT blocked (exit=$prot_exit)"
249
+ _fail "tee to .kontourai/flow-agents/current.json NOT blocked (exit=$prot_exit)"
250
250
  fi
251
251
 
252
252
  echo ""
@@ -276,15 +276,15 @@ else
276
276
  fi
277
277
 
278
278
  echo ""
279
- echo "--- AC1.11: tee multi-file — tee /tmp/x .flow-agents/current.json BLOCKED ---"
279
+ echo "--- AC1.11: tee multi-file — tee /tmp/x .kontourai/flow-agents/current.json BLOCKED ---"
280
280
  set +e
281
- prot_out=$(echo '{"tool_name":"Bash","tool_input":{"command":"echo {} | tee /tmp/x .flow-agents/current.json"}}' | node "$PROT" 2>&1)
281
+ prot_out=$(echo '{"tool_name":"Bash","tool_input":{"command":"echo {} | tee /tmp/x .kontourai/flow-agents/current.json"}}' | node "$PROT" 2>&1)
282
282
  prot_exit=$?
283
283
  set -e
284
284
  if [ "$prot_exit" -eq 2 ] && echo "$prot_out" | grep -q "BLOCKED"; then
285
- _pass "tee /tmp/x .flow-agents/current.json blocked (protected 2nd arg checked) (exit 2)"
285
+ _pass "tee /tmp/x .kontourai/flow-agents/current.json blocked (protected 2nd arg checked) (exit 2)"
286
286
  else
287
- _fail "tee /tmp/x .flow-agents/current.json NOT blocked (exit=$prot_exit, out=$prot_out)"
287
+ _fail "tee /tmp/x .kontourai/flow-agents/current.json NOT blocked (exit=$prot_exit, out=$prot_out)"
288
288
  fi
289
289
 
290
290
  echo ""
@@ -325,27 +325,27 @@ echo ""
325
325
  echo "=== AC1 R5a: state.json/trust.bundle protection + interpreter-write detection ==="
326
326
 
327
327
  echo ""
328
- echo "--- AC1.13: Write to .flow-agents/slug/state.json BLOCKED (R5a) ---"
328
+ echo "--- AC1.13: Write to .kontourai/flow-agents/slug/state.json BLOCKED (R5a) ---"
329
329
  set +e
330
- prot_out=$(echo '{"tool_name":"Write","tool_input":{"path":"/repo/.flow-agents/my-slug/state.json"}}' | node "$PROT" 2>&1)
330
+ prot_out=$(echo '{"tool_name":"Write","tool_input":{"path":"/repo/.kontourai/flow-agents/my-slug/state.json"}}' | node "$PROT" 2>&1)
331
331
  prot_exit=$?
332
332
  set -e
333
333
  if [ "$prot_exit" -eq 2 ] && echo "$prot_out" | grep -q "BLOCKED"; then
334
- _pass "Write to .flow-agents/slug/state.json blocked (exit 2)"
334
+ _pass "Write to .kontourai/flow-agents/slug/state.json blocked (exit 2)"
335
335
  else
336
- _fail "Write to .flow-agents/slug/state.json NOT blocked (exit=$prot_exit)"
336
+ _fail "Write to .kontourai/flow-agents/slug/state.json NOT blocked (exit=$prot_exit)"
337
337
  fi
338
338
 
339
339
  echo ""
340
- echo "--- AC1.14: Edit to .flow-agents/slug/trust.bundle BLOCKED (R5a) ---"
340
+ echo "--- AC1.14: Edit to .kontourai/flow-agents/slug/trust.bundle BLOCKED (R5a) ---"
341
341
  set +e
342
- prot_out=$(echo '{"tool_name":"Edit","tool_input":{"path":"/repo/.flow-agents/my-slug/trust.bundle"}}' | node "$PROT" 2>&1)
342
+ prot_out=$(echo '{"tool_name":"Edit","tool_input":{"path":"/repo/.kontourai/flow-agents/my-slug/trust.bundle"}}' | node "$PROT" 2>&1)
343
343
  prot_exit=$?
344
344
  set -e
345
345
  if [ "$prot_exit" -eq 2 ] && echo "$prot_out" | grep -q "BLOCKED"; then
346
- _pass "Edit to .flow-agents/slug/trust.bundle blocked (exit 2)"
346
+ _pass "Edit to .kontourai/flow-agents/slug/trust.bundle blocked (exit 2)"
347
347
  else
348
- _fail "Edit to .flow-agents/slug/trust.bundle NOT blocked (exit=$prot_exit)"
348
+ _fail "Edit to .kontourai/flow-agents/slug/trust.bundle NOT blocked (exit=$prot_exit)"
349
349
  fi
350
350
 
351
351
  echo ""
@@ -363,25 +363,49 @@ fi
363
363
  echo ""
364
364
  echo "--- AC1.16: Bash redirect > to state.json BLOCKED (R5a: REDIRECT_PROTECTED_RE extended) ---"
365
365
  set +e
366
- prot_out=$(echo '{"tool_name":"Bash","tool_input":{"command":"echo {} > .flow-agents/slug/state.json"}}' | node "$PROT" 2>&1)
366
+ prot_out=$(echo '{"tool_name":"Bash","tool_input":{"command":"echo {} > .kontourai/flow-agents/slug/state.json"}}' | node "$PROT" 2>&1)
367
367
  prot_exit=$?
368
368
  set -e
369
369
  if [ "$prot_exit" -eq 2 ] && echo "$prot_out" | grep -q "BLOCKED"; then
370
- _pass "Bash redirect > .flow-agents/slug/state.json blocked (exit 2)"
370
+ _pass "Bash redirect > .kontourai/flow-agents/slug/state.json blocked (exit 2)"
371
371
  else
372
- _fail "Bash redirect > .flow-agents/slug/state.json NOT blocked (exit=$prot_exit)"
372
+ _fail "Bash redirect > .kontourai/flow-agents/slug/state.json NOT blocked (exit=$prot_exit)"
373
373
  fi
374
374
 
375
375
  echo ""
376
376
  echo "--- AC1.17: tee to trust.bundle BLOCKED (R5a: REDIRECT_PROTECTED_RE extended) ---"
377
377
  set +e
378
- prot_out=$(echo '{"tool_name":"Bash","tool_input":{"command":"echo {} | tee .flow-agents/slug/trust.bundle"}}' | node "$PROT" 2>&1)
378
+ prot_out=$(echo '{"tool_name":"Bash","tool_input":{"command":"echo {} | tee .kontourai/flow-agents/slug/trust.bundle"}}' | node "$PROT" 2>&1)
379
379
  prot_exit=$?
380
380
  set -e
381
381
  if [ "$prot_exit" -eq 2 ] && echo "$prot_out" | grep -q "BLOCKED"; then
382
- _pass "tee to .flow-agents/slug/trust.bundle blocked (exit 2)"
382
+ _pass "tee to .kontourai/flow-agents/slug/trust.bundle blocked (exit 2)"
383
383
  else
384
- _fail "tee to .flow-agents/slug/trust.bundle NOT blocked (exit=$prot_exit)"
384
+ _fail "tee to .kontourai/flow-agents/slug/trust.bundle NOT blocked (exit=$prot_exit)"
385
+ fi
386
+
387
+ echo ""
388
+ echo "--- AC1.17b: Write to goal-fit block streak BLOCKED ---"
389
+ set +e
390
+ prot_out=$(echo '{"tool_name":"Write","tool_input":{"path":"/repo/.kontourai/flow-agents/.goal-fit-block-streak.json"}}' | node "$PROT" 2>&1)
391
+ prot_exit=$?
392
+ set -e
393
+ if [ "$prot_exit" -eq 2 ] && echo "$prot_out" | grep -q "BLOCKED"; then
394
+ _pass "Write to .kontourai/flow-agents/.goal-fit-block-streak.json blocked (exit 2)"
395
+ else
396
+ _fail "Write to .kontourai/flow-agents/.goal-fit-block-streak.json NOT blocked (exit=$prot_exit)"
397
+ fi
398
+
399
+ echo ""
400
+ echo "--- AC1.17c: tee to goal-fit block streak BLOCKED ---"
401
+ set +e
402
+ prot_out=$(echo '{"tool_name":"Bash","tool_input":{"command":"echo {} | tee .kontourai/flow-agents/.goal-fit-block-streak.json"}}' | node "$PROT" 2>&1)
403
+ prot_exit=$?
404
+ set -e
405
+ if [ "$prot_exit" -eq 2 ] && echo "$prot_out" | grep -q "BLOCKED"; then
406
+ _pass "tee to .kontourai/flow-agents/.goal-fit-block-streak.json blocked (exit 2)"
407
+ else
408
+ _fail "tee to .kontourai/flow-agents/.goal-fit-block-streak.json NOT blocked (exit=$prot_exit)"
385
409
  fi
386
410
 
387
411
  echo ""
@@ -487,11 +511,11 @@ echo ""
487
511
  echo "--- AC1.R6a.2: Gate blocks npm test || exit 0 (claimed pass via laundered command) ---"
488
512
  R6LA="$TMP/r6la-laundering"
489
513
  seed_repo_inprogress "$R6LA" "launder-r6"
490
- python3 - "$R6LA/.flow-agents/launder-r6/trust.bundle" "launder-r6" "npm test || exit 0" << 'PY'
514
+ python3 - "$R6LA/.kontourai/flow-agents/launder-r6/trust.bundle" "launder-r6" "npm test || exit 0" << 'PY'
491
515
  import json, sys
492
516
  bp, slug, cmd = sys.argv[1], sys.argv[2], sys.argv[3]
493
517
  bundle = {
494
- "schemaVersion": 3, "source": "flow-agents/workflow-sidecar",
518
+ "schemaVersion": 5, "source": "flow-agents/workflow-sidecar",
495
519
  "claims": [{"id":"c1","subjectId":slug+"/tests","subjectType":"flow-step",
496
520
  "claimType":"builder.verify.tests","fieldOrBehavior":cmd,
497
521
  "value":"pass","impactLevel":"high","status":"verified",
@@ -505,7 +529,7 @@ bundle = {
505
529
  json.dump(bundle, open(bp, 'w'))
506
530
  PY
507
531
  printf '%s\n' '{"command":"npm test || exit 0","observedResult":"pass","exitCode":0,"capturedAt":"2026-06-27T00:00:00Z","source":"postToolUse-capture"}' \
508
- > "$R6LA/.flow-agents/launder-r6/command-log.jsonl"
532
+ > "$R6LA/.kontourai/flow-agents/launder-r6/command-log.jsonl"
509
533
 
510
534
  set +e
511
535
  r6la_out=$(run_gate "$R6LA")
@@ -526,11 +550,11 @@ echo ""
526
550
  echo "--- AC1.R6a.3: Gate blocks npm test || echo ok (claimed pass via laundered command) ---"
527
551
  R6LB="$TMP/r6lb-laundering"
528
552
  seed_repo_inprogress "$R6LB" "launder-r6b"
529
- python3 - "$R6LB/.flow-agents/launder-r6b/trust.bundle" "launder-r6b" "npm test || echo ok" << 'PY'
553
+ python3 - "$R6LB/.kontourai/flow-agents/launder-r6b/trust.bundle" "launder-r6b" "npm test || echo ok" << 'PY'
530
554
  import json, sys
531
555
  bp, slug, cmd = sys.argv[1], sys.argv[2], sys.argv[3]
532
556
  bundle = {
533
- "schemaVersion": 3, "source": "test",
557
+ "schemaVersion": 5, "source": "test",
534
558
  "claims": [{"id":"c1","subjectId":slug+"/tests","subjectType":"flow-step",
535
559
  "claimType":"builder.verify.tests","fieldOrBehavior":cmd,
536
560
  "value":"pass","impactLevel":"high","status":"verified",
@@ -544,7 +568,7 @@ bundle = {
544
568
  json.dump(bundle, open(bp, 'w'))
545
569
  PY
546
570
  printf '%s\n' '{"command":"npm test || echo ok","observedResult":"pass","exitCode":0,"capturedAt":"2026-06-27T00:00:00Z","source":"postToolUse-capture"}' \
547
- > "$R6LB/.flow-agents/launder-r6b/command-log.jsonl"
571
+ > "$R6LB/.kontourai/flow-agents/launder-r6b/command-log.jsonl"
548
572
 
549
573
  set +e
550
574
  r6lb_out=$(run_gate "$R6LB")
@@ -560,11 +584,11 @@ echo ""
560
584
  echo "--- AC1.R6a.4: Gate blocks npm test || /bin/true (claimed pass via laundered command) ---"
561
585
  R6LC="$TMP/r6lc-laundering"
562
586
  seed_repo_inprogress "$R6LC" "launder-r6c"
563
- python3 - "$R6LC/.flow-agents/launder-r6c/trust.bundle" "launder-r6c" "npm test || /bin/true" << 'PY'
587
+ python3 - "$R6LC/.kontourai/flow-agents/launder-r6c/trust.bundle" "launder-r6c" "npm test || /bin/true" << 'PY'
564
588
  import json, sys
565
589
  bp, slug, cmd = sys.argv[1], sys.argv[2], sys.argv[3]
566
590
  bundle = {
567
- "schemaVersion": 3, "source": "test",
591
+ "schemaVersion": 5, "source": "test",
568
592
  "claims": [{"id":"c1","subjectId":slug+"/tests","subjectType":"flow-step",
569
593
  "claimType":"builder.verify.tests","fieldOrBehavior":cmd,
570
594
  "value":"pass","impactLevel":"high","status":"verified",
@@ -578,7 +602,7 @@ bundle = {
578
602
  json.dump(bundle, open(bp, 'w'))
579
603
  PY
580
604
  printf '%s\n' '{"command":"npm test || /bin/true","observedResult":"pass","exitCode":0,"capturedAt":"2026-06-27T00:00:00Z","source":"postToolUse-capture"}' \
581
- > "$R6LC/.flow-agents/launder-r6c/command-log.jsonl"
605
+ > "$R6LC/.kontourai/flow-agents/launder-r6c/command-log.jsonl"
582
606
 
583
607
  set +e
584
608
  r6lc_out=$(run_gate "$R6LC")
@@ -594,11 +618,11 @@ echo ""
594
618
  echo "--- AC1.R6a.5: Bare 'npm test' with PASS log NOT blocked (no over-flag) ---"
595
619
  R6LD="$TMP/r6ld-legit"
596
620
  seed_repo_inprogress "$R6LD" "legit-r6"
597
- python3 - "$R6LD/.flow-agents/legit-r6/trust.bundle" "legit-r6" << 'PY'
621
+ python3 - "$R6LD/.kontourai/flow-agents/legit-r6/trust.bundle" "legit-r6" << 'PY'
598
622
  import json, sys
599
623
  bp, slug = sys.argv[1], sys.argv[2]
600
624
  bundle = {
601
- "schemaVersion": 3, "source": "test",
625
+ "schemaVersion": 5, "source": "test",
602
626
  "claims": [{"id":"c1","subjectId":slug+"/tests","subjectType":"flow-step",
603
627
  "claimType":"builder.verify.tests","fieldOrBehavior":"npm test",
604
628
  "value":"pass","impactLevel":"high","status":"verified",
@@ -612,7 +636,7 @@ bundle = {
612
636
  json.dump(bundle, open(bp, 'w'))
613
637
  PY
614
638
  printf '%s\n' '{"command":"npm test","observedResult":"pass","exitCode":0,"capturedAt":"2026-06-27T00:00:00Z","source":"postToolUse-capture"}' \
615
- > "$R6LD/.flow-agents/legit-r6/command-log.jsonl"
639
+ > "$R6LD/.kontourai/flow-agents/legit-r6/command-log.jsonl"
616
640
 
617
641
  set +e
618
642
  r6ld_out=$(run_gate "$R6LD")
@@ -726,8 +750,8 @@ AC2D="$TMP/ac2-hard"
726
750
  seed_repo_inprogress "$AC2D" "ac2hard"
727
751
  # Evidence claims npm test passed, but log shows it failed → caught false-completion
728
752
  printf '%s' '{"schema_version":"1.0","task_slug":"ac2hard","verdict":"pass","checks":[{"id":"unit-tests","kind":"command","status":"pass","command":"npm test","summary":"passed"}]}' \
729
- > "$AC2D/.flow-agents/ac2hard/evidence.json"
730
- write_chained_fail_log "$AC2D/.flow-agents/ac2hard/command-log.jsonl" "npm test"
753
+ > "$AC2D/.kontourai/flow-agents/ac2hard/evidence.json"
754
+ write_chained_fail_log "$AC2D/.kontourai/flow-agents/ac2hard/command-log.jsonl" "npm test"
731
755
 
732
756
  set +e
733
757
  ac2h_1=$(FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_MAX_BLOCKS=1 FLOW_AGENTS_GOAL_FIT_BACKSTOP=skip \
@@ -758,9 +782,9 @@ echo "--- AC2.2: MAX_BLOCKS=1 with soft/advisory-only streak → may release (ex
758
782
  AC2S="$TMP/ac2-soft"
759
783
  seed_repo_inprogress "$AC2S" "ac2soft" "execution" "executing"
760
784
  # Write a clean bundle with no disputed claims (just a workflow-state warning from status)
761
- write_clean_bundle "$AC2S/.flow-agents/ac2soft/trust.bundle"
785
+ write_clean_bundle "$AC2S/.kontourai/flow-agents/ac2soft/trust.bundle"
762
786
  # Write empty command-log so missing-log doesn't fire
763
- printf '' > "$AC2S/.flow-agents/ac2soft/command-log.jsonl"
787
+ printf '' > "$AC2S/.kontourai/flow-agents/ac2soft/command-log.jsonl"
764
788
 
765
789
  set +e
766
790
  # First call: blocks (streak=1, max=1 → already at max → soft: release)
@@ -769,8 +793,8 @@ ac2s_1=$(FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_MAX_BLOCKS=1 FLOW_
769
793
  ac2s_1_exit=$?
770
794
  set -e
771
795
 
772
- if [ "$ac2s_1_exit" -eq 0 ] && echo "$ac2s_1" | grep -q "RELEASED after"; then
773
- _pass "AC2: soft/advisory-only streak releases at MAX_BLOCKS=1 (exit 0, RELEASED after)"
796
+ if [ "$ac2s_1_exit" -eq 0 ] && echo "$ac2s_1" | grep -q "released — the same gap(s) blocked"; then
797
+ _pass "AC2: soft/advisory-only streak releases at MAX_BLOCKS=1 (exit 0, released notice)"
774
798
  else
775
799
  _fail "AC2: soft streak should release at MAX_BLOCKS=1. exit=$ac2s_1_exit out=${ac2s_1:0:300}"
776
800
  fi
@@ -801,15 +825,15 @@ cp "$ROOT/scripts/lib/command-log-chain.js" "$ISO_LIBDIR/"
801
825
 
802
826
  # Create isolated node context that can't find @kontourai/surface
803
827
  ISO_DIR="$TMP/surface-iso"
804
- mkdir -p "$ISO_DIR/repo/.flow-agents/surftest"
828
+ mkdir -p "$ISO_DIR/repo/.kontourai/flow-agents/surftest"
805
829
  mkdir -p "$ISO_DIR/lib"
806
830
  cp "$GATE" "$ISO_DIR/stop-goal-fit.js"
807
831
  cp "$ROOT/scripts/hooks/lib/local-artifact-paths.js" "$ISO_DIR/lib/"
808
832
  printf '# Repo\n' > "$ISO_DIR/repo/AGENTS.md"
809
833
  # Non-terminal session (execution phase, in_progress status)
810
834
  printf '%s' '{"schema_version":"1.0","task_slug":"surftest","status":"in_progress","phase":"execution","updated_at":"2026-06-27T00:00:00Z","next_action":{"status":"in_progress","summary":"running"}}' \
811
- > "$ISO_DIR/repo/.flow-agents/surftest/state.json"
812
- cat > "$ISO_DIR/repo/.flow-agents/surftest/surftest--deliver.md" << 'MD'
835
+ > "$ISO_DIR/repo/.kontourai/flow-agents/surftest/state.json"
836
+ cat > "$ISO_DIR/repo/.kontourai/flow-agents/surftest/surftest--deliver.md" << 'MD'
813
837
  # surftest
814
838
 
815
839
  branch: main
@@ -819,9 +843,9 @@ type: deliver
819
843
  ## Definition Of Done
820
844
  - [ ] tests pass
821
845
  MD
822
- write_high_impact_bundle "$ISO_DIR/repo/.flow-agents/surftest/trust.bundle" "surftest" "verified"
846
+ write_high_impact_bundle "$ISO_DIR/repo/.kontourai/flow-agents/surftest/trust.bundle" "surftest" "verified"
823
847
  # Empty log (non-missing)
824
- printf '' > "$ISO_DIR/repo/.flow-agents/surftest/command-log.jsonl"
848
+ printf '' > "$ISO_DIR/repo/.kontourai/flow-agents/surftest/command-log.jsonl"
825
849
 
826
850
  set +e
827
851
  # Run in isolated dir with NODE_PATH=$ISO_DIR so @kontourai/surface cannot be found
@@ -847,14 +871,14 @@ echo ""
847
871
  echo "--- AC3.1b: Low-impact-only bundle with unavailable surface → NOT blocked ---"
848
872
 
849
873
  ISO2_DIR="$TMP/surface-iso2"
850
- mkdir -p "$ISO2_DIR/repo/.flow-agents/lowtest"
874
+ mkdir -p "$ISO2_DIR/repo/.kontourai/flow-agents/lowtest"
851
875
  mkdir -p "$ISO2_DIR/lib"
852
876
  cp "$GATE" "$ISO2_DIR/stop-goal-fit.js"
853
877
  cp "$ROOT/scripts/hooks/lib/local-artifact-paths.js" "$ISO2_DIR/lib/"
854
878
  printf '# Repo\n' > "$ISO2_DIR/repo/AGENTS.md"
855
879
  printf '%s' '{"schema_version":"1.0","task_slug":"lowtest","status":"in_progress","phase":"execution","updated_at":"2026-06-27T00:00:00Z","next_action":{"status":"in_progress","summary":"running"}}' \
856
- > "$ISO2_DIR/repo/.flow-agents/lowtest/state.json"
857
- cat > "$ISO2_DIR/repo/.flow-agents/lowtest/lowtest--deliver.md" << 'MD'
880
+ > "$ISO2_DIR/repo/.kontourai/flow-agents/lowtest/state.json"
881
+ cat > "$ISO2_DIR/repo/.kontourai/flow-agents/lowtest/lowtest--deliver.md" << 'MD'
858
882
  # lowtest
859
883
 
860
884
  branch: main
@@ -865,11 +889,11 @@ type: deliver
865
889
  - [ ] tests pass
866
890
  MD
867
891
  # Low-impact claim only
868
- python3 - "$ISO2_DIR/repo/.flow-agents/lowtest/trust.bundle" "lowtest" << 'PY'
892
+ python3 - "$ISO2_DIR/repo/.kontourai/flow-agents/lowtest/trust.bundle" "lowtest" << 'PY'
869
893
  import json, sys
870
894
  bp, slug = sys.argv[1], sys.argv[2]
871
895
  bundle = {
872
- "schemaVersion": 3, "source": "test",
896
+ "schemaVersion": 5, "source": "test",
873
897
  "claims": [{
874
898
  "id": "c-low",
875
899
  "subjectId": slug + "/docs",
@@ -886,7 +910,7 @@ bundle = {
886
910
  }
887
911
  json.dump(bundle, open(bp, 'w'))
888
912
  PY
889
- printf '' > "$ISO2_DIR/repo/.flow-agents/lowtest/command-log.jsonl"
913
+ printf '' > "$ISO2_DIR/repo/.kontourai/flow-agents/lowtest/command-log.jsonl"
890
914
 
891
915
  set +e
892
916
  surf2_out=$(NODE_PATH="$ISO2_DIR" FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_MAX_BLOCKS=100000 \
@@ -919,10 +943,10 @@ seed_repo_inprogress "$AC3D" "postex" "execution" "in_progress"
919
943
  # This simulates a session where the agent ran commands (evidence.execution.label present)
920
944
  # but deleted command-log.jsonl. The #216 guard uses execution.label to distinguish this
921
945
  # from a legitimate no-command session (no execution.label → no missing-log warning).
922
- python3 - "$AC3D/.flow-agents/postex/trust.bundle" << 'PY'
946
+ python3 - "$AC3D/.kontourai/flow-agents/postex/trust.bundle" << 'PY'
923
947
  import json, sys
924
948
  bundle = {
925
- "schemaVersion": 3, "source": "test",
949
+ "schemaVersion": 5, "source": "test",
926
950
  "claims": [],
927
951
  "evidence": [{
928
952
  "id": "ev-captured", "claimId": None,
@@ -962,7 +986,7 @@ echo "--- AC3.2b: Pre-execution session (planning/planned) with no log → NOT b
962
986
 
963
987
  AC3P="$TMP/ac3-preexec"
964
988
  seed_repo_preexec "$AC3P" "preex"
965
- write_clean_bundle "$AC3P/.flow-agents/preex/trust.bundle"
989
+ write_clean_bundle "$AC3P/.kontourai/flow-agents/preex/trust.bundle"
966
990
  # No command-log.jsonl — pre-execution sessions have no commands yet
967
991
 
968
992
  set +e
@@ -984,11 +1008,11 @@ echo "--- AC3.2c: Post-execution session WITH command log present → NOT falsel
984
1008
 
985
1009
  AC3C="$TMP/ac3-cleanlog"
986
1010
  seed_repo_inprogress "$AC3C" "cleanlog" "execution" "in_progress"
987
- write_clean_bundle "$AC3C/.flow-agents/cleanlog/trust.bundle"
988
- write_chained_fail_log "$AC3C/.flow-agents/cleanlog/command-log.jsonl" "echo hello"
1011
+ write_clean_bundle "$AC3C/.kontourai/flow-agents/cleanlog/trust.bundle"
1012
+ write_chained_fail_log "$AC3C/.kontourai/flow-agents/cleanlog/command-log.jsonl" "echo hello"
989
1013
  # Override: mark the command as pass in evidence to avoid false-completion blocking
990
1014
  printf '%s' '{"schema_version":"1.0","task_slug":"cleanlog","verdict":"pass","checks":[]}' \
991
- > "$AC3C/.flow-agents/cleanlog/evidence.json"
1015
+ > "$AC3C/.kontourai/flow-agents/cleanlog/evidence.json"
992
1016
 
993
1017
  set +e
994
1018
  ac3c_out=$(FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_MAX_BLOCKS=100000 \
@@ -1051,9 +1075,9 @@ echo "=== Over-block check: normal session NOT falsely blocked ==="
1051
1075
 
1052
1076
  OVR="$TMP/overblock"
1053
1077
  seed_repo_inprogress "$OVR" "normal" "execution" "in_progress"
1054
- write_clean_bundle "$OVR/.flow-agents/normal/trust.bundle"
1078
+ write_clean_bundle "$OVR/.kontourai/flow-agents/normal/trust.bundle"
1055
1079
  # Write a valid command log (empty — no claims to cross-reference)
1056
- printf '' > "$OVR/.flow-agents/normal/command-log.jsonl"
1080
+ printf '' > "$OVR/.kontourai/flow-agents/normal/command-log.jsonl"
1057
1081
 
1058
1082
  set +e
1059
1083
  ovr_out=$(FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_MAX_BLOCKS=100000 \
@@ -1143,7 +1167,7 @@ if [ "$errors" -eq 0 ]; then
1143
1167
  echo " R6b: delivery/trust.bundle + delivery/trust.checkpoint.json protected (Write/Edit + > + cp/mv blocked)"
1144
1168
  echo " INCOMPLETE: process substitution, runtime path construction, rsync/scp/dd evade"
1145
1169
  echo " AC2: Hard blocks (false-completion, integrity failure) NOT auto-released by MAX_BLOCKS"
1146
- echo " INCOMPLETE: agent can reset streak by deleting .goal-fit-block-streak.json via Bash"
1170
+ echo " INCOMPLETE: agent can reset streak with runtime-constructed paths"
1147
1171
  echo " AC3.1: surface-unavailable + high-impact → FULL_BLOCK warning; low-impact non-blocking"
1148
1172
  echo " INCOMPLETE: agent could delete @kontourai/surface to force this path"
1149
1173
  echo " AC3.2: missing log in post-execution → FULL_BLOCK; pre-execution → not blocked"
@@ -62,14 +62,14 @@ seed_trust_bundle() {
62
62
 
63
63
  cat > "$dir/trust.bundle" <<JSON
64
64
  {
65
- "schemaVersion": 3,
65
+ "schemaVersion": 5,
66
66
  "source": "gate-review-test;statusFunctionVersion=1",
67
67
  "claims": [
68
68
  {
69
69
  "id": "$claimId",
70
70
  "subjectType": "workflow-check",
71
71
  "subjectId": "$slug/unit-tests",
72
- "surface": "flow-agents.workflow",
72
+ "facet": "flow-agents.workflow",
73
73
  "claimType": "workflow.check.test",
74
74
  "fieldOrBehavior": "unit tests pass",
75
75
  "value": "pass",
@@ -256,7 +256,7 @@ mkdir -p "$AC2MB_DIR"
256
256
  # Seed: empty bundle (no claims) + no block + expected criterion absent → missed_block
257
257
  cat > "$AC2MB_DIR/trust.bundle" <<JSON
258
258
  {
259
- "schemaVersion": 3,
259
+ "schemaVersion": 5,
260
260
  "source": "gate-review-test;statusFunctionVersion=1",
261
261
  "claims": [],
262
262
  "evidence": [],
@@ -34,21 +34,21 @@ c2=$(run_block "$TMPDIR_EVAL/b2.err")
34
34
  c3=$(run_block "$TMPDIR_EVAL/b3.err")
35
35
  c4=$(run_block "$TMPDIR_EVAL/b4.err")
36
36
 
37
- [[ "$c1" -eq 2 ]] && rg -q 'BLOCK 1/3' "$TMPDIR_EVAL/b1.err" \
38
- && _pass "first identical block exits 2 (BLOCK 1/3)" \
39
- || _fail "first block should exit 2 BLOCK 1/3 (got $c1: $(cat "$TMPDIR_EVAL/b1.err"))"
37
+ [[ "$c1" -eq 2 ]] && rg -q 'Stop blocked .* \(block 1; after 3 identical blocks' "$TMPDIR_EVAL/b1.err" \
38
+ && _pass "first identical block exits 2 (block 1; after 3 identical blocks)" \
39
+ || _fail "first block should exit 2, block 1/3 shape (got $c1: $(cat "$TMPDIR_EVAL/b1.err"))"
40
40
 
41
- [[ "$c2" -eq 2 ]] && rg -q 'BLOCK 2/3' "$TMPDIR_EVAL/b2.err" \
42
- && _pass "second identical block exits 2 (BLOCK 2/3)" \
43
- || _fail "second block should exit 2 BLOCK 2/3 (got $c2)"
41
+ [[ "$c2" -eq 2 ]] && rg -q 'Stop blocked .* \(block 2; after 3 identical blocks' "$TMPDIR_EVAL/b2.err" \
42
+ && _pass "second identical block exits 2 (block 2; after 3 identical blocks)" \
43
+ || _fail "second block should exit 2, block 2/3 shape (got $c2)"
44
44
 
45
- [[ "$c3" -eq 0 ]] && rg -q 'RELEASED after 3 consecutive identical blocks' "$TMPDIR_EVAL/b3.err" \
45
+ [[ "$c3" -eq 0 ]] && rg -q 'released the same gap\(s\) blocked 3x without progress' "$TMPDIR_EVAL/b3.err" \
46
46
  && _pass "third identical block RELEASES (exit 0, loud notice)" \
47
47
  || _fail "third block should release exit 0 (got $c3: $(cat "$TMPDIR_EVAL/b3.err"))"
48
48
 
49
- [[ "$c4" -eq 2 ]] && rg -q 'BLOCK 1/3' "$TMPDIR_EVAL/b4.err" \
49
+ [[ "$c4" -eq 2 ]] && rg -q 'Stop blocked .* \(block 1; after 3 identical blocks' "$TMPDIR_EVAL/b4.err" \
50
50
  && _pass "streak resets after release (next block is 1/3 again)" \
51
- || _fail "post-release block should reset to BLOCK 1/3 (got $c4)"
51
+ || _fail "post-release block should reset to block 1/3 shape (got $c4)"
52
52
 
53
53
  # A changing goal-fit gap must reset the streak (progress, not a stuck loop).
54
54
  printf '%s' "$PAYLOAD" | FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_MAX_BLOCKS=3 node "$ROOT/scripts/hooks/stop-goal-fit.js" >/dev/null 2>/dev/null
@@ -56,7 +56,7 @@ printf '%s' "$PAYLOAD" | FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_MA
56
56
  printf '# Stuck\n\nbranch: main\nstatus: verifying\ntype: deliver\n\n## Plan\n\nDifferent.\n' \
57
57
  > "$REPO/.flow-agents/stuck/stuck--deliver.md"
58
58
  cd=$(run_block "$TMPDIR_EVAL/bd.err")
59
- [[ "$cd" -eq 2 ]] && rg -q 'BLOCK 1/3' "$TMPDIR_EVAL/bd.err" \
59
+ [[ "$cd" -eq 2 ]] && rg -q 'Stop blocked .* \(block 1; after 3 identical blocks' "$TMPDIR_EVAL/bd.err" \
60
60
  && _pass "changed goal-fit gap resets the streak to 1/3" \
61
61
  || _fail "changed gap should reset streak (got $cd: $(cat "$TMPDIR_EVAL/bd.err"))"
62
62
 
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env bash
2
+ # test_goal_fit_ghost_session.sh — WS8 (AC10) stop-goal-fit hardening.
3
+ #
4
+ # (a) GHOST-SESSION: when current.json names a slug whose session directory does not exist,
5
+ # the hook LOGS the staleness and does NOT resurface an abandoned, markdown-only
6
+ # directory (no state.json / trust.bundle) as "the active session" via a global mtime
7
+ # scan. A directory is eligible as active only with real sidecar presence.
8
+ # (b) MALFORMED-EVIDENCE: a kind:"command" acceptance evidence ref whose excerpt is prose
9
+ # (a sentence, not a runnable command) is classified `malformed-evidence` — it is NOT
10
+ # spawned via `bash -lc "<a sentence>"` and NOT conflated with a caught false-completion.
11
+ #
12
+ # Deterministic, no model spend, self-cleaning.
13
+ # Usage: bash evals/integration/test_goal_fit_ghost_session.sh
14
+
15
+ set -uo pipefail
16
+
17
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
18
+ HOOK="$ROOT/scripts/hooks/stop-goal-fit.js"
19
+
20
+ TMP="$(mktemp -d)"
21
+ errors=0
22
+ _pass() { echo " PASS: $1"; }
23
+ _fail() { echo " FAIL: $1"; errors=$((errors + 1)); }
24
+ cleanup() { rm -rf "$TMP"; }
25
+ trap cleanup EXIT
26
+
27
+ # ─── (a) GHOST-SESSION ─────────────────────────────────────────────────────────
28
+ echo "=== AC10a: stale current.json slug does not resurface an abandoned markdown-only session ==="
29
+ REPO="$TMP/repo"
30
+ FA="$REPO/.kontourai/flow-agents"
31
+ mkdir -p "$FA/old-abandoned"
32
+ printf '# Test Repo\n' > "$REPO/AGENTS.md"
33
+
34
+ # An abandoned session: ACTIVE status, but only a markdown artifact (no state.json / trust.bundle).
35
+ cat > "$FA/old-abandoned/old-abandoned--deliver.md" <<'MD'
36
+ # Old abandoned session
37
+
38
+ branch: main
39
+ worktree: main
40
+ created: 2026-01-01
41
+ status: executing
42
+ type: deliver
43
+
44
+ ## Plan
45
+
46
+ Abandoned long ago; never had sidecars.
47
+ MD
48
+
49
+ # current.json points at a slug whose directory does NOT exist (stale pointer).
50
+ cat > "$FA/current.json" <<'JSON'
51
+ { "schema_version": "1.0", "active_slug": "ghost-slug", "artifact_dir": "ghost-slug", "updated_at": "2026-07-02T00:00:00Z", "owner": "workflow-sidecar", "source": "ensure-session", "active_agents": [] }
52
+ JSON
53
+
54
+ out_a="$(echo '{"hook_event_name":"Stop","cwd":"'"$REPO"'"}' | node "$HOOK" 2>"$TMP/a.err")"
55
+ exit_a=$?
56
+ err_a="$(cat "$TMP/a.err")"
57
+
58
+ if echo "$err_a" | grep -q 'no such session directory exists'; then
59
+ _pass "staleness is LOGGED (stale current.json slug is visible, not silently swallowed)"
60
+ else
61
+ _fail "expected a staleness log for the stale current.json slug; stderr: $err_a"
62
+ fi
63
+
64
+ if echo "$err_a" | grep -q 'old-abandoned'; then
65
+ _fail "abandoned markdown-only session was resurfaced as active (should be filtered — no sidecar): $err_a"
66
+ else
67
+ _pass "abandoned markdown-only session (no state.json/trust.bundle) was NOT resurfaced as active"
68
+ fi
69
+
70
+ if [[ $exit_a -eq 0 ]]; then
71
+ _pass "no block from a stale pointer + abandoned session (exit 0)"
72
+ else
73
+ _fail "expected exit 0 (nothing genuinely active), got $exit_a"
74
+ fi
75
+
76
+ # ─── (b) MALFORMED-EVIDENCE ─────────────────────────────────────────────────────
77
+ echo ""
78
+ echo "=== AC10b: prose kind:command evidence ref is classified malformed, never spawned as bash ==="
79
+ if node - "$ROOT" << 'NODE'
80
+ const path = require('path');
81
+ const mod = require(path.join(process.argv[2], 'scripts/hooks/stop-goal-fit.js'));
82
+ const check = { id: 'unit', command: '', kind: 'test', status: 'not_verified' };
83
+ const prose = { criteria: [ { id: 'unit', evidence_refs: [ { kind: 'command', excerpt: 'Manually verify the dashboard renders the export button and click it.' } ] } ] };
84
+ const runnable = { criteria: [ { id: 'unit', evidence_refs: [ { kind: 'command', excerpt: 'npm test' } ] } ] };
85
+ const r1 = mod.resolveTrustedCommand('/repo', '/repo/.kontourai/flow-agents/x', check, prose);
86
+ const r2 = mod.resolveTrustedCommand('/repo', '/repo/.kontourai/flow-agents/x', check, runnable);
87
+ if (!(r1 && r1.malformed && !r1.argv)) { console.error('prose ref NOT classified malformed: ' + JSON.stringify(r1)); process.exit(1); }
88
+ if (!(r2 && Array.isArray(r2.argv) && r2.argv[0] === 'bash' && r2.argv[2] === 'npm test')) { console.error('runnable ref did not resolve to an argv: ' + JSON.stringify(r2)); process.exit(1); }
89
+ process.exit(0);
90
+ NODE
91
+ then
92
+ _pass "prose acceptance command ref → {malformed} (no argv); runnable ref → executable argv"
93
+ else
94
+ _fail "resolveTrustedCommand mishandled prose vs runnable command refs"
95
+ fi
96
+
97
+ echo ""
98
+ if [[ $errors -eq 0 ]]; then
99
+ echo "test_goal_fit_ghost_session: all checks passed."
100
+ exit 0
101
+ else
102
+ echo "test_goal_fit_ghost_session: $errors check(s) failed."
103
+ exit 1
104
+ fi