@kontourai/flow-agents 2.3.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. package/.github/CODEOWNERS +16 -0
  2. package/.github/workflows/ci.yml +44 -0
  3. package/.github/workflows/trust-reconcile.yml +62 -4
  4. package/AGENTS.md +4 -4
  5. package/CHANGELOG.md +62 -0
  6. package/CONTEXT.md +35 -0
  7. package/README.md +9 -3
  8. package/agents/dev.json +1 -1
  9. package/agents/tool-code-reviewer.json +1 -1
  10. package/agents/tool-planner.json +3 -3
  11. package/agents/tool-verifier.json +3 -3
  12. package/build/src/cli/assignment-provider.d.ts +1 -0
  13. package/build/src/cli/assignment-provider.js +748 -0
  14. package/build/src/cli/console-learning-projection.js +3 -2
  15. package/build/src/cli/effective-assignment-provider-settings.d.ts +1 -0
  16. package/build/src/cli/effective-assignment-provider-settings.js +125 -0
  17. package/build/src/cli/init.js +104 -21
  18. package/build/src/cli/kit.js +37 -6
  19. package/build/src/cli/pull-work-provider.js +1 -1
  20. package/build/src/cli/usage-feedback.js +3 -3
  21. package/build/src/cli/validate-hook-influence.js +1 -0
  22. package/build/src/cli/validate-workflow-artifacts.js +27 -7
  23. package/build/src/cli/workflow-artifact-cleanup-audit.js +36 -2
  24. package/build/src/cli/workflow-sidecar.d.ts +14 -7
  25. package/build/src/cli/workflow-sidecar.js +938 -168
  26. package/build/src/cli.js +6 -0
  27. package/build/src/flow-kit/validate.d.ts +23 -0
  28. package/build/src/flow-kit/validate.js +67 -1
  29. package/build/src/index.d.ts +1 -1
  30. package/build/src/index.js +1 -1
  31. package/build/src/lib/flow-resolver.d.ts +6 -4
  32. package/build/src/lib/flow-resolver.js +125 -58
  33. package/build/src/lib/local-artifact-root.d.ts +14 -2
  34. package/build/src/lib/local-artifact-root.js +22 -5
  35. package/build/src/lib/workflow-learning-projection.js +2 -2
  36. package/build/src/runtime-adapters.d.ts +12 -0
  37. package/build/src/runtime-adapters.js +56 -16
  38. package/build/src/tools/build-universal-bundles.js +49 -16
  39. package/build/src/tools/generate-context-map.js +10 -8
  40. package/build/src/tools/validate-source-tree.js +24 -1
  41. package/console.telemetry.json +22 -0
  42. package/context/contracts/artifact-contract.md +40 -7
  43. package/context/contracts/assignment-provider-contract.md +239 -0
  44. package/context/contracts/builder-kit-workflow-state-contract.md +5 -2
  45. package/context/contracts/decision-registry-contract.md +265 -0
  46. package/context/contracts/delivery-contract.md +3 -1
  47. package/context/contracts/execution-contract.md +25 -0
  48. package/context/contracts/governance-adapter-contract.md +2 -0
  49. package/context/contracts/knowledge-store-contract.md +197 -0
  50. package/context/contracts/planning-contract.md +4 -1
  51. package/context/contracts/review-contract.md +7 -3
  52. package/context/contracts/sandbox-policy.md +2 -0
  53. package/context/contracts/standing-directives.md +13 -0
  54. package/context/contracts/verification-contract.md +11 -1
  55. package/context/contracts/work-item-contract.md +3 -1
  56. package/context/deferred/parallelization.md +1 -1
  57. package/context/gate-awareness.md +4 -4
  58. package/context/scripts/git-status.sh +2 -2
  59. package/context/scripts/hooks/config-protection.js +502 -2
  60. package/context/scripts/hooks/lib/config-protection-remedies.js +69 -0
  61. package/context/scripts/hooks/run-hook.js +14 -1
  62. package/context/scripts/hooks/stop-goal-fit.js +1140 -99
  63. package/context/scripts/hooks/workflow-steering.js +212 -6
  64. package/context/settings/assignment-provider-settings.json +33 -0
  65. package/docs/adr/0007-flow-skill-kit-tool-boundary.md +2 -0
  66. package/docs/adr/0015-flow-flow-agents-boundary-reconciliation.md +35 -0
  67. package/docs/adr/0019-kit-dependency-ownership.md +62 -0
  68. package/docs/adr/0020-trust-reconcile-manifest-and-claim-classification.md +290 -0
  69. package/docs/adr/0021-assignment-leases-and-stale-claim-takeover.md +221 -0
  70. package/docs/adr/0022-fail-closed-delivery-reconciliation-with-governed-exemptions.md +463 -0
  71. package/docs/agent-system-guidebook.md +3 -3
  72. package/docs/agent-usage-feedback-loop.md +6 -6
  73. package/docs/context-map.md +10 -7
  74. package/docs/decisions/decision-records.md +57 -0
  75. package/docs/decisions/index.md +17 -0
  76. package/docs/decisions/knowledge-store-provider.md +51 -0
  77. package/docs/decisions/model-routing.md +63 -0
  78. package/docs/decisions/promotion-gate.md +52 -0
  79. package/docs/decisions/standing-directives.md +66 -0
  80. package/docs/developer-architecture.md +1 -1
  81. package/docs/fixture-ownership.md +4 -0
  82. package/docs/flow-kit-repository-contract.md +5 -5
  83. package/docs/getting-started.md +12 -2
  84. package/docs/integrations/harness-install.md +2 -1
  85. package/docs/kit-authoring-guide.md +64 -5
  86. package/docs/knowledge-kit.md +5 -1
  87. package/docs/learnings/2026-07-improvement-program.md +203 -0
  88. package/docs/migrations.md +6 -5
  89. package/docs/north-star.md +2 -2
  90. package/docs/operating-layers.md +4 -3
  91. package/docs/repository-structure.md +5 -5
  92. package/docs/skills-map.md +8 -8
  93. package/docs/spec/runtime-hook-surface.md +19 -15
  94. package/docs/spikes/graph-provider-2026-07.md +155 -0
  95. package/docs/standards-register.md +7 -7
  96. package/docs/trust-anchor-adoption.md +105 -4
  97. package/docs/work-item-adapters.md +1 -1
  98. package/docs/workflow-artifact-lifecycle.md +72 -9
  99. package/docs/workflow-eval-strategy.md +3 -3
  100. package/docs/workflow-shared-contracts.md +3 -2
  101. package/docs/workflow-usage-guide.md +260 -21
  102. package/evals/acceptance/DEMO-false-completion.md +20 -11
  103. package/evals/acceptance/prove-capture-teeth-declared.sh +15 -15
  104. package/evals/acceptance/prove-capture-teeth.sh +11 -11
  105. package/evals/acceptance/test_kiro_harness.sh +1 -1
  106. package/evals/ci/antigaming-suite.sh +5 -0
  107. package/evals/ci/run-baseline.sh +71 -1
  108. package/evals/fixtures/assignment-provider/actor-a.json +6 -0
  109. package/evals/fixtures/assignment-provider/actor-b.json +6 -0
  110. package/evals/fixtures/assignment-provider/github-issue-claimed.json +27 -0
  111. package/evals/fixtures/assignment-provider/github-issue-unassigned.json +7 -0
  112. package/evals/fixtures/assignment-provider/liveness-fresh.json +9 -0
  113. package/evals/fixtures/assignment-provider/liveness-stale.json +9 -0
  114. package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/flows/review.flow.json +26 -0
  115. package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/kit.json +13 -0
  116. package/evals/fixtures/flow-kit-repository/valid-with-dependency/flows/review.flow.json +26 -0
  117. package/evals/fixtures/flow-kit-repository/valid-with-dependency/kit.json +13 -0
  118. package/evals/fixtures/hook-influence/cases.json +32 -0
  119. package/evals/fixtures/pull-work-provider/github-issues.json +6 -6
  120. package/evals/fixtures/trust-reconcile-exploits/fabricated-attestation.json +59 -0
  121. package/evals/fixtures/trust-reconcile-exploits/no-label-bypass.json +36 -0
  122. package/evals/fixtures/trust-reconcile-exploits/skip-assumed-bypass.json +59 -0
  123. package/evals/fixtures/trust-reconcile-exploits/status-misassertion.json +48 -0
  124. package/evals/fixtures/trust-reconcile-exploits/waived-command-check.json +44 -0
  125. package/evals/fixtures/trust-reconcile-mixed-bundle/mixed-bundle.json +159 -0
  126. package/evals/fixtures/trust-reconcile-ws3/ws3-bundle.json +920 -0
  127. package/evals/integration/test_actor_identity.sh +254 -0
  128. package/evals/integration/test_assignment_provider_github.sh +318 -0
  129. package/evals/integration/test_assignment_provider_local_file.sh +222 -0
  130. package/evals/integration/test_builder_step_producers.sh +33 -23
  131. package/evals/integration/test_bundle_install.sh +22 -16
  132. package/evals/integration/test_bundle_lifecycle.sh +11 -11
  133. package/evals/integration/test_captured_fail_reconciliation.sh +50 -50
  134. package/evals/integration/test_checkpoint_signing.sh +43 -0
  135. package/evals/integration/test_claim_lookup.sh +4 -4
  136. package/evals/integration/test_codex_hook_resolution.sh +114 -0
  137. package/evals/integration/test_command_log_concurrency.sh +8 -8
  138. package/evals/integration/test_command_log_fork_classification.sh +3 -3
  139. package/evals/integration/test_command_log_integrity.sh +16 -16
  140. package/evals/integration/test_console_learning_projection.sh +1 -1
  141. package/evals/integration/test_critique_supersession_roundtrip.sh +182 -0
  142. package/evals/integration/test_dual_emit_flow_step.sh +145 -0
  143. package/evals/integration/test_enforcer_expects_driven.sh +12 -12
  144. package/evals/integration/test_evidence_capture_hook.sh +14 -13
  145. package/evals/integration/test_fixture_retirement_audit.sh +2 -2
  146. package/evals/integration/test_flow_agents_statusline.sh +2 -2
  147. package/evals/integration/test_flow_kit_install_git.sh +52 -0
  148. package/evals/integration/test_flow_kit_repository.sh +2 -0
  149. package/evals/integration/test_flowdef_session_activation.sh +6 -6
  150. package/evals/integration/test_flowdef_union_floor_regression.sh +429 -0
  151. package/evals/integration/test_gate_bypass_chain.sh +52 -40
  152. package/evals/integration/test_gate_lockdown.sh +97 -73
  153. package/evals/integration/test_gate_review_inquiry_records.sh +3 -3
  154. package/evals/integration/test_goal_fit_escape_hatch.sh +10 -10
  155. package/evals/integration/test_goal_fit_ghost_session.sh +104 -0
  156. package/evals/integration/test_goal_fit_hook.sh +32 -32
  157. package/evals/integration/test_goal_fit_rederive.sh +9 -9
  158. package/evals/integration/test_hook_category_behaviors.sh +103 -0
  159. package/evals/integration/test_hook_influence_cases.sh +1 -0
  160. package/evals/integration/test_install_merge.sh +262 -1
  161. package/evals/integration/test_kit_identity_trust.sh +6 -6
  162. package/evals/integration/test_liveness_conflict_injection.sh +587 -0
  163. package/evals/integration/test_liveness_heartbeat.sh +677 -0
  164. package/evals/integration/test_liveness_verdict.sh +394 -0
  165. package/evals/integration/test_local_flow_kit_install.sh +15 -0
  166. package/evals/integration/test_phase_map_and_gate_claim.sh +63 -11
  167. package/evals/integration/test_promote_gate.sh +178 -0
  168. package/evals/integration/test_publish_delivery.sh +23 -6
  169. package/evals/integration/test_pull_work_assignment_join.sh +132 -0
  170. package/evals/integration/test_pull_work_liveness_preflight.sh +394 -0
  171. package/evals/integration/test_pull_work_provider.sh +2 -2
  172. package/evals/integration/test_reconcile_soundness.sh +37 -13
  173. package/evals/integration/test_resolvefirststep_security.sh +22 -0
  174. package/evals/integration/test_runtime_adapter_activation.sh +87 -18
  175. package/evals/integration/test_session_resume_roundtrip.sh +147 -0
  176. package/evals/integration/test_sidecar_field_preservation.sh +249 -0
  177. package/evals/integration/test_trust_reconcile.sh +11 -10
  178. package/evals/integration/test_trust_reconcile_manifest.sh +79 -0
  179. package/evals/integration/test_trust_reconcile_mixed_bundle.sh +96 -0
  180. package/evals/integration/test_trust_reconcile_negatives.sh +759 -0
  181. package/evals/integration/test_usage_feedback_global.sh +5 -5
  182. package/evals/integration/test_validate_artifacts_portability.sh +60 -0
  183. package/evals/integration/test_verify_cli.sh +2 -2
  184. package/evals/integration/test_veritas_governance_kit.sh +117 -0
  185. package/evals/integration/test_workflow_artifact_cleanup_audit.sh +26 -1
  186. package/evals/integration/test_workflow_artifacts.sh +33 -0
  187. package/evals/integration/test_workflow_sidecar_writer.sh +802 -74
  188. package/evals/integration/test_workflow_steering_hook.sh +175 -5
  189. package/evals/lib/codex-provider.sh +1 -1
  190. package/evals/lib/node.sh +19 -1
  191. package/evals/run.sh +32 -0
  192. package/evals/static/test_decisions.sh +150 -0
  193. package/evals/static/test_flowdef_codeowners_coverage.sh +62 -0
  194. package/evals/static/test_knowledge_providers.sh +23 -0
  195. package/evals/static/test_package.sh +19 -10
  196. package/evals/static/test_universal_bundles.sh +48 -3
  197. package/evals/static/test_workflow_skills.sh +41 -8
  198. package/kits/builder/flows/build.flow.json +3 -74
  199. package/kits/builder/flows/publish-learn.flow.json +90 -0
  200. package/kits/builder/kit.json +11 -0
  201. package/kits/builder/skills/builder-shape/SKILL.md +1 -1
  202. package/kits/builder/skills/deliver/SKILL.md +32 -11
  203. package/kits/builder/skills/design-probe/SKILL.md +4 -4
  204. package/kits/builder/skills/evidence-gate/SKILL.md +26 -1
  205. package/kits/builder/skills/execute-plan/SKILL.md +2 -2
  206. package/kits/builder/skills/fix-bug/SKILL.md +2 -0
  207. package/kits/builder/skills/gate-review/SKILL.md +6 -6
  208. package/kits/builder/skills/idea-to-backlog/SKILL.md +1 -1
  209. package/kits/builder/skills/learning-review/SKILL.md +7 -7
  210. package/kits/builder/skills/pickup-probe/SKILL.md +5 -4
  211. package/kits/builder/skills/plan-work/SKILL.md +27 -5
  212. package/kits/builder/skills/pull-work/SKILL.md +148 -5
  213. package/kits/builder/skills/release-readiness/SKILL.md +4 -4
  214. package/kits/builder/skills/review-work/SKILL.md +24 -1
  215. package/kits/builder/skills/tdd-workflow/SKILL.md +2 -0
  216. package/kits/builder/skills/verify-work/SKILL.md +8 -1
  217. package/kits/catalog.json +6 -0
  218. package/kits/knowledge/kit.json +35 -0
  219. package/kits/knowledge/providers/conformance/fixtures/git-repo/CONTEXT.md +12 -0
  220. package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/decisions/old-sprocket-shape.md +13 -0
  221. package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/decisions/sprocket-shape.md +14 -0
  222. package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/decisions/widget-format.md +14 -0
  223. package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/learnings/fixture-learning.md +7 -0
  224. package/kits/knowledge/providers/conformance/fixtures/work-item/issues.json +30 -0
  225. package/kits/knowledge/providers/conformance/suite.test.js +125 -0
  226. package/kits/knowledge/providers/git-repo/index.js +236 -0
  227. package/kits/knowledge/providers/health/health-pass.test.js +99 -0
  228. package/kits/knowledge/providers/health/index.js +153 -0
  229. package/kits/knowledge/providers/index.js +24 -0
  230. package/kits/knowledge/providers/lib/model.js +91 -0
  231. package/kits/knowledge/providers/lib/schema-validate.js +119 -0
  232. package/kits/knowledge/providers/markdown-vault/index.js +169 -0
  233. package/kits/knowledge/providers/work-item/index.js +204 -0
  234. package/kits/veritas-governance/adapter/readiness-to-trust-bundle.mjs +178 -0
  235. package/kits/veritas-governance/docs/README.md +75 -0
  236. package/kits/veritas-governance/fixtures/readiness/not-ready.readiness-report.json +4645 -0
  237. package/kits/veritas-governance/fixtures/readiness/ready.readiness-report.json +4403 -0
  238. package/kits/veritas-governance/flows/readiness-check.flow.json +35 -0
  239. package/kits/veritas-governance/kit.json +16 -0
  240. package/package.json +11 -5
  241. package/packaging/README.md +2 -2
  242. package/packaging/conformance/fixtures/config-protection--allow-read-state-json.json +20 -0
  243. package/packaging/conformance/fixtures/config-protection--block-write-state-json.json +20 -0
  244. package/packaging/conformance/fixtures/stop-goal-fit--block-bundle-disputed-claim.json +1 -1
  245. package/packaging/conformance/fixtures/stop-goal-fit--block-capture-contradicts-claimed-pass.json +1 -1
  246. package/packaging/manifest.json +9 -10
  247. package/schemas/assignment-provider-settings.schema.json +125 -0
  248. package/schemas/decision-record.schema.json +109 -0
  249. package/schemas/knowledge/edge.schema.json +54 -0
  250. package/schemas/knowledge/health-report.schema.json +45 -0
  251. package/schemas/knowledge/node.schema.json +49 -0
  252. package/schemas/knowledge/proposal.schema.json +53 -0
  253. package/schemas/workflow-evidence.schema.json +1 -1
  254. package/schemas/workflow-state.schema.json +5 -0
  255. package/scripts/README.md +8 -3
  256. package/scripts/check-content-boundary.cjs +1 -1
  257. package/scripts/check-decisions.cjs +356 -0
  258. package/scripts/ci/derive-claim-status.mjs +74 -0
  259. package/scripts/ci/trust-reconcile.js +957 -103
  260. package/scripts/git-status.sh +2 -2
  261. package/scripts/hooks/claude-telemetry-hook.js +37 -3
  262. package/scripts/hooks/codex-telemetry-hook.js +36 -2
  263. package/scripts/hooks/config-protection.js +102 -30
  264. package/scripts/hooks/evidence-capture.js +3 -3
  265. package/scripts/hooks/lib/actor-identity.js +368 -0
  266. package/scripts/hooks/lib/config-protection-remedies.js +69 -0
  267. package/scripts/hooks/lib/liveness-heartbeat.js +361 -0
  268. package/scripts/hooks/lib/liveness-policy.js +127 -0
  269. package/scripts/hooks/lib/liveness-read.js +105 -12
  270. package/scripts/hooks/lib/liveness-write.js +46 -0
  271. package/scripts/hooks/lib/local-artifact-paths.js +12 -6
  272. package/scripts/hooks/opencode-telemetry-hook.js +27 -1
  273. package/scripts/hooks/pi-telemetry-hook.js +27 -1
  274. package/scripts/hooks/stop-goal-fit.js +157 -26
  275. package/scripts/hooks/workflow-steering.js +77 -3
  276. package/scripts/install-codex-home.sh +138 -38
  277. package/scripts/statusline/flow-agents-statusline.js +2 -2
  278. package/src/cli/assignment-provider.ts +845 -0
  279. package/src/cli/console-learning-projection.ts +3 -2
  280. package/src/cli/effective-assignment-provider-settings.ts +112 -0
  281. package/src/cli/init.ts +101 -21
  282. package/src/cli/kit.ts +37 -6
  283. package/src/cli/public-api.test.mjs +58 -6
  284. package/src/cli/pull-work-provider.ts +1 -1
  285. package/src/cli/trust-bundle-policy-order.test.mjs +87 -0
  286. package/src/cli/usage-feedback.ts +3 -3
  287. package/src/cli/validate-hook-influence.ts +1 -0
  288. package/src/cli/validate-workflow-artifacts.ts +27 -7
  289. package/src/cli/veritas-readiness-adapter.test.mjs +267 -0
  290. package/src/cli/workflow-artifact-cleanup-audit.ts +35 -2
  291. package/src/cli/workflow-sidecar.ts +933 -168
  292. package/src/cli.ts +6 -0
  293. package/src/flow-kit/validate.ts +74 -1
  294. package/src/index.ts +6 -2
  295. package/src/lib/flow-resolver.ts +123 -55
  296. package/src/lib/local-artifact-root.ts +24 -5
  297. package/src/lib/workflow-learning-projection.ts +2 -2
  298. package/src/runtime-adapters.ts +61 -15
  299. package/src/tools/build-universal-bundles.ts +49 -16
  300. package/src/tools/generate-context-map.ts +10 -8
  301. package/src/tools/validate-source-tree.ts +24 -1
@@ -3,13 +3,21 @@ import fs from "node:fs";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import path from "node:path";
5
5
  import { loadJson, readText, root, walkFiles, writeText } from "./common.js";
6
+ import { DURABLE_FLOW_AGENTS_DIR, FLOW_AGENTS_RUNTIME_DIR } from "../lib/local-artifact-root.js";
6
7
 
7
8
  type Agent = Record<string, unknown> & { name: string; prompt: string };
8
9
  const dist = process.env.FLOW_AGENTS_DIST_DIR ? path.resolve(process.env.FLOW_AGENTS_DIST_DIR) : path.join(root, "dist");
9
10
  const manifest = loadJson<Record<string, any>>(path.join(root, "packaging/manifest.json"));
10
11
  const pkgVersion: string = (loadJson<Record<string, unknown>>(path.join(root, "package.json")) as Record<string, string>)["version"] ?? "0.0.0";
12
+ const runtimeTaskDir = FLOW_AGENTS_RUNTIME_DIR;
13
+ const durableInstallRecordRel = `${DURABLE_FLOW_AGENTS_DIR}/install.json`;
11
14
  const textExtensions = new Set([".css", ".html", ".js", ".json", ".md", ".sh", ".toml", ".txt", ".yaml", ".yml", ".ts"]);
12
15
  const dropDiagnostics: string[] = [];
16
+ // Set by collectAllSkills() when two kits (or a kit and the top-level skills/
17
+ // dir) declare the same skill directory name. Reported via the same
18
+ // console.error + process.exitCode diagnostic idiom as the rest of this file
19
+ // (see main()) instead of an uncaught thrown Error / stack trace.
20
+ let skillCollisionDiagnostic: string | null = null;
13
21
  const printDiagnostics = !["0", "false", "no"].includes(String(process.env.FLOW_AGENTS_EXPORT_DIAGNOSTICS ?? "1").toLowerCase());
14
22
 
15
23
  /**
@@ -21,17 +29,29 @@ const printDiagnostics = !["0", "false", "no"].includes(String(process.env.FLOW_
21
29
  */
22
30
  function collectAllSkills(): Array<{ name: string; src: string }> {
23
31
  const results: Array<{ name: string; src: string }> = [];
24
- const seen = new Set<string>();
32
+ const seen = new Map<string, string>(); // skill name -> source description of first declaration
33
+ const collisions: string[] = [];
34
+
35
+ // Compiled host bundles ship skills flat at .claude/skills/<name>/SKILL.md etc., so
36
+ // the install name (skill directory name) must be globally unique across skills/ and
37
+ // every kit. A duplicate is a build-FAILING collision, never a silent drop — the
38
+ // previous Set-based dedupe silently kept only the first and discarded the rest.
39
+ const recordSkill = (name: string, src: string, source: string): void => {
40
+ const prior = seen.get(name);
41
+ if (prior !== undefined) {
42
+ collisions.push(` - '${name}' is declared by both ${prior} and ${source}`);
43
+ return;
44
+ }
45
+ seen.set(name, source);
46
+ results.push({ name, src });
47
+ };
25
48
 
26
49
  // 1. Top-level skills/ directory (tools pending reclassification).
27
50
  const skillsDir = path.join(root, "skills");
28
51
  if (fs.existsSync(skillsDir)) {
29
52
  for (const skill of fs.readdirSync(skillsDir).sort()) {
30
53
  const skillPath = path.join(skillsDir, skill, "SKILL.md");
31
- if (fs.existsSync(skillPath) && !seen.has(skill)) {
32
- seen.add(skill);
33
- results.push({ name: skill, src: skillPath });
34
- }
54
+ if (fs.existsSync(skillPath)) recordSkill(skill, skillPath, "skills/");
35
55
  }
36
56
  }
37
57
 
@@ -52,14 +72,19 @@ function collectAllSkills(): Array<{ name: string; src: string }> {
52
72
  // Derive install name from the directory containing SKILL.md (one level up).
53
73
  const absPath = path.resolve(path.join(kitsDir, kitName), relPath);
54
74
  const skillName = path.basename(path.dirname(absPath));
55
- if (fs.existsSync(absPath) && !seen.has(skillName)) {
56
- seen.add(skillName);
57
- results.push({ name: skillName, src: absPath });
58
- }
75
+ if (fs.existsSync(absPath)) recordSkill(skillName, absPath, `kits/${kitName}`);
59
76
  }
60
77
  }
61
78
  }
62
79
 
80
+ if (collisions.length) {
81
+ skillCollisionDiagnostic =
82
+ "flow-agents: skill name collision — skill directory names must be unique across " +
83
+ "skills/ and all kits/*/kit.json:\n" +
84
+ collisions.join("\n") +
85
+ "\nRename one of the colliding skill directories so every compiled bundle skill has a unique install name.";
86
+ }
87
+
63
88
  return results.sort((a, b) => a.name.localeCompare(b.name));
64
89
  }
65
90
 
@@ -181,7 +206,7 @@ function generatedAgentsSummary(agents: Agent[]): string {
181
206
  function exportRootAgentsMd(label: string, agents: Agent[], taskDir: string): string {
182
207
  return `# Universal Agent Bundle (${label})\n\nThis bundle was generated from the canonical source in this repo. Treat the repo root as the source of truth and regenerate the bundle instead of editing exported agent files by hand.\n\n## Shared Conventions\n\n- \`skills/\`, \`context/\`, \`powers/\`, \`prompts/\`, \`scripts/\`, and \`evals/\` were copied from the canonical source.\n- Cross-session task artifacts should live under \`${taskDir}\`.\n- Kiro-only hook wiring was stripped from exported non-Kiro agents to keep the package portable.\n\n## Exported Agents\n\n${generatedAgentsSummary(agents)}\n`;
183
208
  }
184
- const CODEX_LIVE_HOOKS_README = `\n## Running with hooks active (live)\n\n\`install.sh\` lays the bundle into a workspace, but a live Codex session needs a \`CODEX_HOME\` that has both the bundle's hooks/scripts AND your real credentials. Use the dedicated installer, which flattens the config to the home root and copies your auth from \`~/.codex\`:\n\n\`\`\`bash\nbash scripts/install-codex-home.sh "$HOME/.flow-agents/codex"\nCODEX_HOME="$HOME/.flow-agents/codex" codex exec --dangerously-bypass-hook-trust -C /path/to/project "<prompt>"\n\`\`\`\n\nThe goal-fit Stop hook then enforces by default (\`FLOW_AGENTS_GOAL_FIT_MODE=block\`); set it to \`warn\` or \`off\` to override.\n`;
209
+ const CODEX_LIVE_HOOKS_README = `\n## Running with hooks active (live)\n\n\`install.sh\` lays the bundle into a workspace, but a live Codex session needs a \`CODEX_HOME\` that has both the bundle's hooks/scripts AND your real credentials. Use the dedicated installer, which defaults to \`CODEX_HOME\` when set and otherwise \`~/.codex\`, flattens the config to the home root, and copies your auth from \`~/.codex\` when installing elsewhere:\n\n\`\`\`bash\nbash scripts/install-codex-home.sh\ncodex exec --dangerously-bypass-hook-trust -C /path/to/project \"<prompt>\"\n\`\`\`\n\nPass a positional destination to install into an explicit alternate Codex home.\n\nThe goal-fit Stop hook then enforces by default (\`FLOW_AGENTS_GOAL_FIT_MODE=block\`); set it to \`warn\` or \`off\` to override.\n`;
185
210
  function exportTargetReadme(label: string, installHint: string, extra = ""): string {
186
211
  return `# ${label} Bundle\n\nGenerated from the canonical source in this repository.\n\n## Install\n\n\`\`\`bash\n${installHint}\n\`\`\`\n\nThe install ships the full standalone base (skills, agents, powers) plus the\nFlow Kits. Kit depth is activated through the Kit Catalog, not at install time.\n\n## Contents\n\n- Harness-specific agents\n- Shared skills\n- Shared context, powers, prompts, scripts, and evals\n${extra}`;
187
212
  }
@@ -260,7 +285,7 @@ function claudePolicy(event: string, script: string, envPrefix = ""): string {
260
285
  return `bash -lc 'root="\${CLAUDE_PROJECT_DIR:-$(pwd)}"; ${envPrefix}node "$root/scripts/hooks/claude-hook-adapter.js" ${event} ${script.replace(/\.js$/, "")} ${script} default'`;
261
286
  }
262
287
  function codexRoot(scriptPath: string): string {
263
- return `root="\${CODEX_HOME:-}"; if [ -z "$root" ] || [ ! -f "$root/${scriptPath}" ]; then root=$(git rev-parse --show-toplevel 2>/dev/null || pwd); fi`;
288
+ return `root="\${CODEX_HOME:-}"; if [ -z "$root" ] || [ ! -f "$root/${scriptPath}" ]; then root=$(git rev-parse --show-toplevel 2>/dev/null || pwd); fi; if [ ! -f "$root/${scriptPath}" ] && [ -f "$HOME/.codex/${scriptPath}" ]; then root="$HOME/.codex"; fi; if [ ! -f "$root/${scriptPath}" ]; then echo "flow-agents: hook script not found at $root/${scriptPath} (checked \\$CODEX_HOME, git toplevel/cwd, and \\$HOME/.codex) - skipping hook" >&2; exit 0; fi`;
264
289
  }
265
290
  function codexTelemetry(event: string): string {
266
291
  if (event === "PermissionRequest") return `bash -lc '${codexRoot("scripts/telemetry/telemetry.sh")}; bash "$root/scripts/telemetry/telemetry.sh" permissionRequest dev'`;
@@ -330,9 +355,9 @@ function installScript(label: string, defaultDestDisplay: string, token?: string
330
355
  const requiredCheck = destRequired ? `if [[ -z "$DEST" ]]; then\n usage\n exit 2\nfi\n` : "";
331
356
  const usageDest = destRequired ? "/path/to/workspace" : defaultDestDisplay;
332
357
  const mergeBlock = mergeConfig
333
- ? `\nif command -v node >/dev/null 2>&1; then\n node "$DEST/scripts/install-merge.js" --config "$DEST/${mergeConfig.configRelPath}" --managed-hooks "$SRC/${mergeConfig.managedConfigRelPath}" --version "${mergeConfig.version}" --install-record "$DEST/.flow-agents/install.json" --runtime "${mergeConfig.runtime}" || true\nfi`
358
+ ? `\nif command -v node >/dev/null 2>&1; then\n node "$DEST/scripts/install-merge.js" --config "$DEST/${mergeConfig.configRelPath}" --managed-hooks "$SRC/${mergeConfig.managedConfigRelPath}" --version "${mergeConfig.version}" --install-record "$DEST/${durableInstallRecordRel}" --runtime "${mergeConfig.runtime}" || true\nfi`
334
359
  : stampConfig
335
- ? `\nif command -v node >/dev/null 2>&1; then\n node "$DEST/scripts/install-merge.js" --stamp-only --version "${stampConfig.version}" --install-record "$DEST/.flow-agents/install.json" --runtime "${stampConfig.runtime}" || true\nfi`
360
+ ? `\nif command -v node >/dev/null 2>&1; then\n node "$DEST/scripts/install-merge.js" --stamp-only --version "${stampConfig.version}" --install-record "$DEST/${durableInstallRecordRel}" --runtime "${stampConfig.runtime}" || true\nfi`
336
361
  : "";
337
362
  return `#!/usr/bin/env bash\nset -euo pipefail\n\nusage() {\n cat >&2 <<'EOF'\nusage: bash install.sh ${usageDest} [options]\n\nOptions:\n --telemetry-sink NAME local-files, local-kontour-console,\n kontour-hosted-console, user-hosted-console,\n or legacy aliases. May be repeated.\n --console-url URL Persist Console telemetry base URL.\n --console-endpoint URL Persist full Console telemetry records endpoint URL.\n --console-token-file PATH\n Read Console telemetry bearer token from a file.\n --console-tenant ID Persist Console tenant identifier.\nEOF\n}\n\nDEST=""\nDEST_SET=0\nCONSOLE_CONFIG_ARGS=()\nwhile [[ $# -gt 0 ]]; do\n case "$1" in\n --telemetry-sink|--telemetry-sinks|--console-url|--console-endpoint|--console-endpoint-url|--console-token-file|--console-tenant|--console-tenant-id)\n [[ $# -ge 2 ]] || { echo "install.sh: $1 requires a value" >&2; exit 2; }\n CONSOLE_CONFIG_ARGS+=("$1" "$2")\n shift 2\n ;;\n --help|-h)\n usage\n exit 0\n ;;\n -*)\n echo "install.sh: unknown option: $1" >&2\n usage\n exit 2\n ;;\n *)\n if [[ "$DEST_SET" -eq 1 ]]; then\n echo "install.sh: unexpected argument: $1" >&2\n usage\n exit 2\n fi\n DEST="$1"\n DEST_SET=1\n shift\n ;;\n esac\ndone${destFallback}\n${requiredCheck}SRC="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"\n\nmkdir -p "$DEST"\nrsync -a ${token ? "--delete " : ""}${mergeConfig ? `--exclude="${mergeConfig.configRelPath}" ` : ""}"$SRC"/ "$DEST"/${replaceBlock}${mergeBlock}\nif [[ \${#CONSOLE_CONFIG_ARGS[@]} -gt 0 || -n "\${FLOW_AGENTS_TELEMETRY_SINK:-}" || -n "\${FLOW_AGENTS_TELEMETRY_SINKS:-}" || -n "\${FLOW_AGENTS_CONSOLE_URL:-}" || -n "\${CONSOLE_TELEMETRY_URL:-}" || -n "\${CONSOLE_URL:-}" || -n "\${FLOW_AGENTS_CONSOLE_TOKEN_FILE:-}" || -n "\${CONSOLE_TELEMETRY_TOKEN_FILE:-}" ]]; then\n bash "$DEST/scripts/telemetry/install-console-config.sh" "$DEST/scripts/telemetry/telemetry.conf" "\${CONSOLE_CONFIG_ARGS[@]}"\nfi\necho "Installed ${label} bundle ${token ? "to" : "into"} $DEST"\n`;
338
363
  }
@@ -341,8 +366,8 @@ function buildBase(agents: Agent[]): void {
341
366
  const bundle = path.join(dist, "base");
342
367
  resetDir(bundle);
343
368
  copySharedContent(bundle, "base", "<bundle-root>");
344
- writeText(path.join(bundle, ".flow-agents", ".gitkeep"), "");
345
- writeText(path.join(bundle, "AGENTS.md"), exportRootAgentsMd("Base", agents, ".flow-agents"));
369
+ writeText(path.join(bundle, runtimeTaskDir, ".gitkeep"), "");
370
+ writeText(path.join(bundle, "AGENTS.md"), exportRootAgentsMd("Base", agents, runtimeTaskDir));
346
371
  writeText(path.join(bundle, "README.md"), exportTargetReadme("Base", "bash install.sh /path/to/workspace"));
347
372
  writeText(path.join(bundle, "install.sh"), installScript("Base", "/path/to/workspace", undefined, undefined, undefined, { runtime: "base", version: pkgVersion }));
348
373
  fs.chmodSync(path.join(bundle, "install.sh"), 0o755);
@@ -354,7 +379,7 @@ function buildKiro(agents: Agent[]): void {
354
379
  resetDir(bundle);
355
380
  copySharedContent(bundle, "kiro", token);
356
381
  for (const spec of agents) writeText(path.join(bundle, "agents", `${spec.name}.json`), sanitizeText(`${JSON.stringify(sanitizeAgentJson(spec), null, 2)}\n`, "kiro", token));
357
- writeText(path.join(bundle, "AGENTS.md"), exportRootAgentsMd("Kiro", agents, ".flow-agents"));
382
+ writeText(path.join(bundle, "AGENTS.md"), exportRootAgentsMd("Kiro", agents, runtimeTaskDir));
358
383
  writeText(path.join(bundle, "README.md"), exportTargetReadme("Kiro", "bash install.sh $HOME/.flow-agents"));
359
384
  writeText(path.join(bundle, "install.sh"), installScript("Kiro", "$HOME/.flow-agents", token, '${FLOW_AGENTS_DEST:-$HOME/.flow-agents}', undefined, { runtime: "kiro", version: pkgVersion }));
360
385
  fs.chmodSync(path.join(bundle, "install.sh"), 0o755);
@@ -699,6 +724,14 @@ function buildCatalog(agents: Agent[]): Record<string, unknown> {
699
724
  }
700
725
  export function main(): number {
701
726
  fs.mkdirSync(dist, { recursive: true });
727
+ // Populate (and, on collision, set) skillCollisionDiagnostic before any
728
+ // build step writes output -- fail fast with a clear diagnostic instead of
729
+ // partially building bundles from a deduped/ambiguous skill set.
730
+ collectAllSkills();
731
+ if (skillCollisionDiagnostic) {
732
+ console.error(skillCollisionDiagnostic);
733
+ return 1;
734
+ }
702
735
  const agents = fs.readdirSync(path.join(root, "agents")).filter((name) => name.endsWith(".json")).sort().map((name) => loadJson<Agent>(path.join(root, "agents", name)));
703
736
  buildBase(agents);
704
737
  buildKiro(agents);
@@ -3,6 +3,7 @@ import fs from "node:fs";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import path from "node:path";
5
5
  import { exists, loadJson, markdownTable, oneLine, readText, rel, root, writeText } from "./common.js";
6
+ import { DURABLE_FLOW_AGENTS_DIR, FLOW_AGENTS_RUNTIME_DIR } from "../lib/local-artifact-root.js";
6
7
 
7
8
  const defaultOutput = path.join(root, "docs/context-map.md");
8
9
  const dirDescriptions: Record<string, string> = {
@@ -22,7 +23,7 @@ const commands = [
22
23
  ["Source tree", "npm run validate:source"],
23
24
  ["Static suite", "bash evals/run.sh static"],
24
25
  ["Integration suite", "bash evals/run.sh integration"],
25
- ["Workflow artifacts", "npm run workflow:validate-artifacts -- --require-sidecars --require-critique .flow-agents/<slug>"],
26
+ ["Workflow artifacts", `npm run workflow:validate-artifacts -- --require-sidecars --require-critique ${FLOW_AGENTS_RUNTIME_DIR}/<slug>`],
26
27
  ["Workflow sidecars", "npm run workflow:sidecar -- --help"],
27
28
  ["Claim lookup", "npm run workflow:sidecar -- claim <id> <dir>"],
28
29
  ["Context map drift", "npm run context-map:check"],
@@ -71,7 +72,8 @@ function repoShape(manifest: Record<string, unknown>): string[][] {
71
72
  rows.push([dir, "optional", "Optional local/user pack copied when present."]);
72
73
  }
73
74
  rows.push(["dist", "generated", "Generated bundle exports. Do not edit by hand."]);
74
- rows.push([".flow-agents", "runtime", "Cross-session workflow artifacts and sidecars. Not committed by default."]);
75
+ rows.push([FLOW_AGENTS_RUNTIME_DIR, "runtime", "Non-durable workflow artifacts, sidecars, and generated projections. Not committed by default."]);
76
+ rows.push([DURABLE_FLOW_AGENTS_DIR, "durable local state", "Explicit Flow Agents config/install state. Not a runtime artifact fallback."]);
75
77
  return rows;
76
78
  }
77
79
 
@@ -147,13 +149,13 @@ function latestRuntimeStates(includeRuntime: boolean): string[] {
147
149
  if (!includeRuntime) {
148
150
  return [
149
151
  "Runtime workflow state is excluded from the committed map.",
150
- "Regenerate locally with `npm run context-map -- --include-runtime` to include recent `.flow-agents` state.",
152
+ `Regenerate locally with \`npm run context-map -- --include-runtime\` to include recent \`${FLOW_AGENTS_RUNTIME_DIR}\` state.`,
151
153
  ];
152
154
  }
153
- const workflowDir = path.join(root, ".flow-agents");
154
- if (!exists(workflowDir)) return ["No local workflow state found under `.flow-agents`."];
155
+ const workflowDir = path.join(root, FLOW_AGENTS_RUNTIME_DIR);
156
+ if (!exists(workflowDir)) return [`No local workflow state found under \`${FLOW_AGENTS_RUNTIME_DIR}\`.`];
155
157
  const states = fs.readdirSync(workflowDir).map((name) => path.join(workflowDir, name, "state.json")).filter(exists).sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs);
156
- if (!states.length) return ["No local workflow state found under `.flow-agents`."];
158
+ if (!states.length) return [`No local workflow state found under \`${FLOW_AGENTS_RUNTIME_DIR}\`.`];
157
159
  const rows = states.slice(0, 8).map((file) => {
158
160
  const data = loadJson<Record<string, unknown>>(file);
159
161
  const next = typeof data.next_action === "object" && data.next_action ? data.next_action as Record<string, unknown> : {};
@@ -171,11 +173,11 @@ function render(includeRuntime: boolean): string {
171
173
  "## How To Use This", "",
172
174
  "- Start here when a session is long, resumed, or context-constrained.",
173
175
  "- Load only the specific skill, contract, schema, or doc that matches the task.",
174
- "- Treat `.flow-agents` as runtime state and `dist/` as generated output.", "",
176
+ `- Treat \`${FLOW_AGENTS_RUNTIME_DIR}\` as runtime state and \`dist/\` as generated output.`, "",
175
177
  "## Repository Shape", "", ...markdownTable(["Path", "Role", "Purpose"], repoShape(manifest)), "",
176
178
  "## Core Commands", "", ...markdownTable(["Use", "Command"], commands), "",
177
179
  "## Workflow Sidecars", "",
178
- "Machine-readable workflow state lives beside Markdown artifacts in `.flow-agents/<slug>/`.", "",
180
+ `Machine-readable workflow state lives beside Markdown artifacts in \`${FLOW_AGENTS_RUNTIME_DIR}/<slug>/\`.`, "",
179
181
  ...markdownTable(["Schema", "Title", "ID"], schemas()), "",
180
182
  "Primary tools: `npm run workflow:sidecar`, `npm run workflow:validate-artifacts`, `scripts/hooks/stop-goal-fit.js`, and `scripts/hooks/workflow-steering.js`.", "",
181
183
  "## Workflow Skills", "", ...markdownTable(["Skill", "Source", "When To Load"], workflowRows), "",
@@ -25,6 +25,15 @@ const mirroredFiles = new Map<string, { mirror: string; allowedDifferences: Arra
25
25
  ["scripts/telemetry/console-presets.sh", { mirror: "context/scripts/telemetry/console-presets.sh", allowedDifferences: [] }],
26
26
  ["scripts/telemetry/install-console-config.sh", { mirror: "context/scripts/telemetry/install-console-config.sh", allowedDifferences: [] }],
27
27
  ["scripts/discover-agents.sh", { mirror: "context/scripts/discover-agents.sh", allowedDifferences: [['ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"', 'ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"']] }],
28
+ // WS8 (AC9): scripts/hooks/* is the actively-maintained source of truth; context/ holds
29
+ // the exported mirror. These four hooks (and the config-protection remedy lib) had drifted
30
+ // silently because nothing validated them. Enforce byte-identical mirrors so future drift
31
+ // fails `npm run validate:source` instead of silently accumulating.
32
+ ["scripts/hooks/config-protection.js", { mirror: "context/scripts/hooks/config-protection.js", allowedDifferences: [] }],
33
+ ["scripts/hooks/lib/config-protection-remedies.js", { mirror: "context/scripts/hooks/lib/config-protection-remedies.js", allowedDifferences: [] }],
34
+ ["scripts/hooks/stop-goal-fit.js", { mirror: "context/scripts/hooks/stop-goal-fit.js", allowedDifferences: [] }],
35
+ ["scripts/hooks/run-hook.js", { mirror: "context/scripts/hooks/run-hook.js", allowedDifferences: [] }],
36
+ ["scripts/hooks/workflow-steering.js", { mirror: "context/scripts/hooks/workflow-steering.js", allowedDifferences: [] }],
28
37
  ]);
29
38
  const publicScriptWrappers = new Map<string, { target: string; significantLines: string[] }>([
30
39
  ["scripts/build-universal-bundles.js", { target: "../build/src/tools/build-universal-bundles.js", significantLines: [
@@ -71,14 +80,20 @@ const hookFilePolicies = new Map<string, { category: string; requiredNeedles: st
71
80
  ["scripts/hooks/utterance-check.js", { category: "policy hook", requiredNeedles: ["Utterance Check Hook", "FLOW_AGENTS_UTTERANCE_CHECK_ENABLED"] }],
72
81
  ["scripts/hooks/workflow-steering.js", { category: "policy hook", requiredNeedles: ["Workflow Steering Hook"] }],
73
82
  ["scripts/hooks/desktop-notify.sh", { category: "local notification helper", requiredNeedles: ["desktop-notify.sh", "osascript"] }],
83
+ ["scripts/hooks/lib/actor-identity.js", { category: "shared hook library", requiredNeedles: ["resolveActor", "FLOW_AGENTS_ACTOR"] }],
74
84
  ["scripts/hooks/lib/audit-transport.sh", { category: "shared hook library", requiredNeedles: ["audit_emit"] }],
85
+ ["scripts/hooks/lib/config-protection-remedies.js", { category: "shared hook library", requiredNeedles: ["SANCTIONED_REMEDIES", "REMEDY_COMMAND_CANDIDATES"] }],
75
86
  ["scripts/hooks/lib/hook-flags.js", { category: "shared hook library", requiredNeedles: ["isHookEnabled"] }],
87
+ ["scripts/hooks/lib/liveness-heartbeat.js", { category: "shared hook library", requiredNeedles: ["maybeEmitHeartbeat", "resolveHeartbeatThrottleSeconds"] }],
88
+ ["scripts/hooks/lib/liveness-policy.js", { category: "shared hook library", requiredNeedles: ["isLivenessEnabled", "resolveTtlSeconds"] }],
76
89
  ["scripts/hooks/lib/liveness-read.js", { category: "shared hook library", requiredNeedles: ["freshHolders", "readLivenessEvents"] }],
90
+ ["scripts/hooks/lib/liveness-write.js", { category: "shared hook library", requiredNeedles: ["appendLivenessEvent", "livenessStreamFile"] }],
77
91
  ["scripts/hooks/lib/local-artifact-paths.js", { category: "shared hook library", requiredNeedles: ["flowAgentsArtifactRoot", "defaultArtifactRootForRead"] }],
78
92
  ["scripts/hooks/lib/patterns.sh", { category: "shared hook library", requiredNeedles: ["_detect_secrets"] }],
79
93
  ["scripts/hooks/lib/resolve-formatter.js", { category: "shared hook library", requiredNeedles: ["resolveFormatter"] }],
80
94
  ]);
81
95
  const fixtureOwnerPolicies = new Map<string, { owners: string[]; classification: string }>([
96
+ ["evals/fixtures/assignment-provider", { owners: ["evals/integration/test_assignment_provider_local_file.sh", "evals/integration/test_assignment_provider_github.sh", "evals/integration/test_pull_work_assignment_join.sh"], classification: "AssignmentProvider local-file and GitHub render/status fixtures (#290)" }],
82
97
  ["evals/fixtures/backlog-provider-settings", { owners: ["evals/integration/test_effective_backlog_settings.sh"], classification: "settings precedence fixtures" }],
83
98
  ["evals/fixtures/builder-kit-workflow-state", { owners: ["evals/static/test_workflow_skills.sh"], classification: "Builder Kit workflow-state fixtures" }],
84
99
  ["evals/fixtures/console-learning-projection", { owners: ["evals/integration/test_console_learning_projection.sh"], classification: "console learning projection fixtures" }],
@@ -88,6 +103,9 @@ const fixtureOwnerPolicies = new Map<string, { owners: string[]; classification:
88
103
  ["evals/fixtures/pull-work-provider", { owners: ["evals/integration/test_pull_work_provider.sh"], classification: "work item provider normalization fixtures" }],
89
104
  ["evals/fixtures/pull-work-wip-shepherding", { owners: ["evals/static/test_workflow_skills.sh"], classification: "WIP shepherding state fixtures" }],
90
105
  ["evals/fixtures/surface-trust", { owners: ["evals/integration/test_workflow_sidecar_writer.sh"], classification: "Surface trust evidence fixtures" }],
106
+ ["evals/fixtures/trust-reconcile-exploits", { owners: ["evals/integration/test_trust_reconcile_negatives.sh"], classification: "WS8 trust-reconcile anti-gaming exploit fixtures (frozen negative regressions)" }],
107
+ ["evals/fixtures/trust-reconcile-mixed-bundle", { owners: ["evals/integration/test_trust_reconcile_mixed_bundle.sh"], classification: "WS8 trust-reconcile mixed-evidence end-to-end proof fixture" }],
108
+ ["evals/fixtures/trust-reconcile-ws3", { owners: ["evals/integration/test_trust_reconcile_negatives.sh"], classification: "WS8 AC6 backward-compat fixture: real ws3-kit-dependencies-namespacing old-style bundle" }],
91
109
  ["evals/fixtures/usage-feedback", { owners: ["evals/integration/test_usage_feedback_import.sh", "evals/integration/test_usage_feedback_outcomes.sh", "evals/integration/test_usage_feedback_report.sh"], classification: "usage feedback import/outcome fixtures" }],
92
110
  ["evals/fixtures/veritas-governance-adapter", { owners: ["evals/integration/test_veritas_governance_adapter.sh"], classification: "Veritas governance adapter fixtures" }],
93
111
  ]);
@@ -98,13 +116,18 @@ const requiredUsageFeedbackFiles = [
98
116
  const fixtureOwnershipSelfAuditRefs = new Set([
99
117
  "evals/integration/test_fixture_retirement_audit.sh",
100
118
  ]);
101
- const pythonInventoryExcludes = new Set([".git", ".flow-agents", "node_modules", ".venv", "dist", "__pycache__", ".pytest_cache", ".cache", "build", "integrations"]);
119
+ const pythonInventoryExcludes = new Set([".git", ".flow-agents", ".kontourai", "node_modules", ".venv", "dist", "__pycache__", ".pytest_cache", ".cache", "build", "integrations"]);
102
120
  const pythonCommandScanRoots = ["README.md", "docs", "context", "skills", "prompts", "agents", "evals", "scripts", "packaging", "package.json"];
103
121
  const allowedPythonCommandFiles = [
104
122
  /^agents\/tool-explore-deps\.json$/,
105
123
  /^evals\/results\//,
106
124
  /^evals\/lib\/python\.sh$/,
107
125
  /(^|\/)telemetry\/lib\/enrich\.sh$/,
126
+ // WS8 (AC10b): stop-goal-fit.js lists python/python3 in its first-token command-RECOGNIZER
127
+ // allowlist (so honest command evidence from a polyglot adopter project is not misclassified
128
+ // as prose). These are literal recognizer tokens, NOT a flow-agents Python dependency — no
129
+ // .py file is ever invoked — so the two byte-identical mirror copies are exempt here.
130
+ /^(context\/)?scripts\/hooks\/stop-goal-fit\.js$/,
108
131
  ];
109
132
 
110
133
  function tryLoadJson(file: string, reporter: Reporter): any {