@kontourai/flow-agents 2.3.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. package/.github/CODEOWNERS +16 -0
  2. package/.github/workflows/ci.yml +44 -0
  3. package/.github/workflows/trust-reconcile.yml +62 -4
  4. package/AGENTS.md +4 -4
  5. package/CHANGELOG.md +62 -0
  6. package/CONTEXT.md +35 -0
  7. package/README.md +9 -3
  8. package/agents/dev.json +1 -1
  9. package/agents/tool-code-reviewer.json +1 -1
  10. package/agents/tool-planner.json +3 -3
  11. package/agents/tool-verifier.json +3 -3
  12. package/build/src/cli/assignment-provider.d.ts +1 -0
  13. package/build/src/cli/assignment-provider.js +748 -0
  14. package/build/src/cli/console-learning-projection.js +3 -2
  15. package/build/src/cli/effective-assignment-provider-settings.d.ts +1 -0
  16. package/build/src/cli/effective-assignment-provider-settings.js +125 -0
  17. package/build/src/cli/init.js +104 -21
  18. package/build/src/cli/kit.js +37 -6
  19. package/build/src/cli/pull-work-provider.js +1 -1
  20. package/build/src/cli/usage-feedback.js +3 -3
  21. package/build/src/cli/validate-hook-influence.js +1 -0
  22. package/build/src/cli/validate-workflow-artifacts.js +27 -7
  23. package/build/src/cli/workflow-artifact-cleanup-audit.js +36 -2
  24. package/build/src/cli/workflow-sidecar.d.ts +14 -7
  25. package/build/src/cli/workflow-sidecar.js +938 -168
  26. package/build/src/cli.js +6 -0
  27. package/build/src/flow-kit/validate.d.ts +23 -0
  28. package/build/src/flow-kit/validate.js +67 -1
  29. package/build/src/index.d.ts +1 -1
  30. package/build/src/index.js +1 -1
  31. package/build/src/lib/flow-resolver.d.ts +6 -4
  32. package/build/src/lib/flow-resolver.js +125 -58
  33. package/build/src/lib/local-artifact-root.d.ts +14 -2
  34. package/build/src/lib/local-artifact-root.js +22 -5
  35. package/build/src/lib/workflow-learning-projection.js +2 -2
  36. package/build/src/runtime-adapters.d.ts +12 -0
  37. package/build/src/runtime-adapters.js +56 -16
  38. package/build/src/tools/build-universal-bundles.js +49 -16
  39. package/build/src/tools/generate-context-map.js +10 -8
  40. package/build/src/tools/validate-source-tree.js +24 -1
  41. package/console.telemetry.json +22 -0
  42. package/context/contracts/artifact-contract.md +40 -7
  43. package/context/contracts/assignment-provider-contract.md +239 -0
  44. package/context/contracts/builder-kit-workflow-state-contract.md +5 -2
  45. package/context/contracts/decision-registry-contract.md +265 -0
  46. package/context/contracts/delivery-contract.md +3 -1
  47. package/context/contracts/execution-contract.md +25 -0
  48. package/context/contracts/governance-adapter-contract.md +2 -0
  49. package/context/contracts/knowledge-store-contract.md +197 -0
  50. package/context/contracts/planning-contract.md +4 -1
  51. package/context/contracts/review-contract.md +7 -3
  52. package/context/contracts/sandbox-policy.md +2 -0
  53. package/context/contracts/standing-directives.md +13 -0
  54. package/context/contracts/verification-contract.md +11 -1
  55. package/context/contracts/work-item-contract.md +3 -1
  56. package/context/deferred/parallelization.md +1 -1
  57. package/context/gate-awareness.md +4 -4
  58. package/context/scripts/git-status.sh +2 -2
  59. package/context/scripts/hooks/config-protection.js +502 -2
  60. package/context/scripts/hooks/lib/config-protection-remedies.js +69 -0
  61. package/context/scripts/hooks/run-hook.js +14 -1
  62. package/context/scripts/hooks/stop-goal-fit.js +1140 -99
  63. package/context/scripts/hooks/workflow-steering.js +212 -6
  64. package/context/settings/assignment-provider-settings.json +33 -0
  65. package/docs/adr/0007-flow-skill-kit-tool-boundary.md +2 -0
  66. package/docs/adr/0015-flow-flow-agents-boundary-reconciliation.md +35 -0
  67. package/docs/adr/0019-kit-dependency-ownership.md +62 -0
  68. package/docs/adr/0020-trust-reconcile-manifest-and-claim-classification.md +290 -0
  69. package/docs/adr/0021-assignment-leases-and-stale-claim-takeover.md +221 -0
  70. package/docs/adr/0022-fail-closed-delivery-reconciliation-with-governed-exemptions.md +463 -0
  71. package/docs/agent-system-guidebook.md +3 -3
  72. package/docs/agent-usage-feedback-loop.md +6 -6
  73. package/docs/context-map.md +10 -7
  74. package/docs/decisions/decision-records.md +57 -0
  75. package/docs/decisions/index.md +17 -0
  76. package/docs/decisions/knowledge-store-provider.md +51 -0
  77. package/docs/decisions/model-routing.md +63 -0
  78. package/docs/decisions/promotion-gate.md +52 -0
  79. package/docs/decisions/standing-directives.md +66 -0
  80. package/docs/developer-architecture.md +1 -1
  81. package/docs/fixture-ownership.md +4 -0
  82. package/docs/flow-kit-repository-contract.md +5 -5
  83. package/docs/getting-started.md +12 -2
  84. package/docs/integrations/harness-install.md +2 -1
  85. package/docs/kit-authoring-guide.md +64 -5
  86. package/docs/knowledge-kit.md +5 -1
  87. package/docs/learnings/2026-07-improvement-program.md +203 -0
  88. package/docs/migrations.md +6 -5
  89. package/docs/north-star.md +2 -2
  90. package/docs/operating-layers.md +4 -3
  91. package/docs/repository-structure.md +5 -5
  92. package/docs/skills-map.md +8 -8
  93. package/docs/spec/runtime-hook-surface.md +19 -15
  94. package/docs/spikes/graph-provider-2026-07.md +155 -0
  95. package/docs/standards-register.md +7 -7
  96. package/docs/trust-anchor-adoption.md +105 -4
  97. package/docs/work-item-adapters.md +1 -1
  98. package/docs/workflow-artifact-lifecycle.md +72 -9
  99. package/docs/workflow-eval-strategy.md +3 -3
  100. package/docs/workflow-shared-contracts.md +3 -2
  101. package/docs/workflow-usage-guide.md +260 -21
  102. package/evals/acceptance/DEMO-false-completion.md +20 -11
  103. package/evals/acceptance/prove-capture-teeth-declared.sh +15 -15
  104. package/evals/acceptance/prove-capture-teeth.sh +11 -11
  105. package/evals/acceptance/test_kiro_harness.sh +1 -1
  106. package/evals/ci/antigaming-suite.sh +5 -0
  107. package/evals/ci/run-baseline.sh +71 -1
  108. package/evals/fixtures/assignment-provider/actor-a.json +6 -0
  109. package/evals/fixtures/assignment-provider/actor-b.json +6 -0
  110. package/evals/fixtures/assignment-provider/github-issue-claimed.json +27 -0
  111. package/evals/fixtures/assignment-provider/github-issue-unassigned.json +7 -0
  112. package/evals/fixtures/assignment-provider/liveness-fresh.json +9 -0
  113. package/evals/fixtures/assignment-provider/liveness-stale.json +9 -0
  114. package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/flows/review.flow.json +26 -0
  115. package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/kit.json +13 -0
  116. package/evals/fixtures/flow-kit-repository/valid-with-dependency/flows/review.flow.json +26 -0
  117. package/evals/fixtures/flow-kit-repository/valid-with-dependency/kit.json +13 -0
  118. package/evals/fixtures/hook-influence/cases.json +32 -0
  119. package/evals/fixtures/pull-work-provider/github-issues.json +6 -6
  120. package/evals/fixtures/trust-reconcile-exploits/fabricated-attestation.json +59 -0
  121. package/evals/fixtures/trust-reconcile-exploits/no-label-bypass.json +36 -0
  122. package/evals/fixtures/trust-reconcile-exploits/skip-assumed-bypass.json +59 -0
  123. package/evals/fixtures/trust-reconcile-exploits/status-misassertion.json +48 -0
  124. package/evals/fixtures/trust-reconcile-exploits/waived-command-check.json +44 -0
  125. package/evals/fixtures/trust-reconcile-mixed-bundle/mixed-bundle.json +159 -0
  126. package/evals/fixtures/trust-reconcile-ws3/ws3-bundle.json +920 -0
  127. package/evals/integration/test_actor_identity.sh +254 -0
  128. package/evals/integration/test_assignment_provider_github.sh +318 -0
  129. package/evals/integration/test_assignment_provider_local_file.sh +222 -0
  130. package/evals/integration/test_builder_step_producers.sh +33 -23
  131. package/evals/integration/test_bundle_install.sh +22 -16
  132. package/evals/integration/test_bundle_lifecycle.sh +11 -11
  133. package/evals/integration/test_captured_fail_reconciliation.sh +50 -50
  134. package/evals/integration/test_checkpoint_signing.sh +43 -0
  135. package/evals/integration/test_claim_lookup.sh +4 -4
  136. package/evals/integration/test_codex_hook_resolution.sh +114 -0
  137. package/evals/integration/test_command_log_concurrency.sh +8 -8
  138. package/evals/integration/test_command_log_fork_classification.sh +3 -3
  139. package/evals/integration/test_command_log_integrity.sh +16 -16
  140. package/evals/integration/test_console_learning_projection.sh +1 -1
  141. package/evals/integration/test_critique_supersession_roundtrip.sh +182 -0
  142. package/evals/integration/test_dual_emit_flow_step.sh +145 -0
  143. package/evals/integration/test_enforcer_expects_driven.sh +12 -12
  144. package/evals/integration/test_evidence_capture_hook.sh +14 -13
  145. package/evals/integration/test_fixture_retirement_audit.sh +2 -2
  146. package/evals/integration/test_flow_agents_statusline.sh +2 -2
  147. package/evals/integration/test_flow_kit_install_git.sh +52 -0
  148. package/evals/integration/test_flow_kit_repository.sh +2 -0
  149. package/evals/integration/test_flowdef_session_activation.sh +6 -6
  150. package/evals/integration/test_flowdef_union_floor_regression.sh +429 -0
  151. package/evals/integration/test_gate_bypass_chain.sh +52 -40
  152. package/evals/integration/test_gate_lockdown.sh +97 -73
  153. package/evals/integration/test_gate_review_inquiry_records.sh +3 -3
  154. package/evals/integration/test_goal_fit_escape_hatch.sh +10 -10
  155. package/evals/integration/test_goal_fit_ghost_session.sh +104 -0
  156. package/evals/integration/test_goal_fit_hook.sh +32 -32
  157. package/evals/integration/test_goal_fit_rederive.sh +9 -9
  158. package/evals/integration/test_hook_category_behaviors.sh +103 -0
  159. package/evals/integration/test_hook_influence_cases.sh +1 -0
  160. package/evals/integration/test_install_merge.sh +262 -1
  161. package/evals/integration/test_kit_identity_trust.sh +6 -6
  162. package/evals/integration/test_liveness_conflict_injection.sh +587 -0
  163. package/evals/integration/test_liveness_heartbeat.sh +677 -0
  164. package/evals/integration/test_liveness_verdict.sh +394 -0
  165. package/evals/integration/test_local_flow_kit_install.sh +15 -0
  166. package/evals/integration/test_phase_map_and_gate_claim.sh +63 -11
  167. package/evals/integration/test_promote_gate.sh +178 -0
  168. package/evals/integration/test_publish_delivery.sh +23 -6
  169. package/evals/integration/test_pull_work_assignment_join.sh +132 -0
  170. package/evals/integration/test_pull_work_liveness_preflight.sh +394 -0
  171. package/evals/integration/test_pull_work_provider.sh +2 -2
  172. package/evals/integration/test_reconcile_soundness.sh +37 -13
  173. package/evals/integration/test_resolvefirststep_security.sh +22 -0
  174. package/evals/integration/test_runtime_adapter_activation.sh +87 -18
  175. package/evals/integration/test_session_resume_roundtrip.sh +147 -0
  176. package/evals/integration/test_sidecar_field_preservation.sh +249 -0
  177. package/evals/integration/test_trust_reconcile.sh +11 -10
  178. package/evals/integration/test_trust_reconcile_manifest.sh +79 -0
  179. package/evals/integration/test_trust_reconcile_mixed_bundle.sh +96 -0
  180. package/evals/integration/test_trust_reconcile_negatives.sh +759 -0
  181. package/evals/integration/test_usage_feedback_global.sh +5 -5
  182. package/evals/integration/test_validate_artifacts_portability.sh +60 -0
  183. package/evals/integration/test_verify_cli.sh +2 -2
  184. package/evals/integration/test_veritas_governance_kit.sh +117 -0
  185. package/evals/integration/test_workflow_artifact_cleanup_audit.sh +26 -1
  186. package/evals/integration/test_workflow_artifacts.sh +33 -0
  187. package/evals/integration/test_workflow_sidecar_writer.sh +802 -74
  188. package/evals/integration/test_workflow_steering_hook.sh +175 -5
  189. package/evals/lib/codex-provider.sh +1 -1
  190. package/evals/lib/node.sh +19 -1
  191. package/evals/run.sh +32 -0
  192. package/evals/static/test_decisions.sh +150 -0
  193. package/evals/static/test_flowdef_codeowners_coverage.sh +62 -0
  194. package/evals/static/test_knowledge_providers.sh +23 -0
  195. package/evals/static/test_package.sh +19 -10
  196. package/evals/static/test_universal_bundles.sh +48 -3
  197. package/evals/static/test_workflow_skills.sh +41 -8
  198. package/kits/builder/flows/build.flow.json +3 -74
  199. package/kits/builder/flows/publish-learn.flow.json +90 -0
  200. package/kits/builder/kit.json +11 -0
  201. package/kits/builder/skills/builder-shape/SKILL.md +1 -1
  202. package/kits/builder/skills/deliver/SKILL.md +32 -11
  203. package/kits/builder/skills/design-probe/SKILL.md +4 -4
  204. package/kits/builder/skills/evidence-gate/SKILL.md +26 -1
  205. package/kits/builder/skills/execute-plan/SKILL.md +2 -2
  206. package/kits/builder/skills/fix-bug/SKILL.md +2 -0
  207. package/kits/builder/skills/gate-review/SKILL.md +6 -6
  208. package/kits/builder/skills/idea-to-backlog/SKILL.md +1 -1
  209. package/kits/builder/skills/learning-review/SKILL.md +7 -7
  210. package/kits/builder/skills/pickup-probe/SKILL.md +5 -4
  211. package/kits/builder/skills/plan-work/SKILL.md +27 -5
  212. package/kits/builder/skills/pull-work/SKILL.md +148 -5
  213. package/kits/builder/skills/release-readiness/SKILL.md +4 -4
  214. package/kits/builder/skills/review-work/SKILL.md +24 -1
  215. package/kits/builder/skills/tdd-workflow/SKILL.md +2 -0
  216. package/kits/builder/skills/verify-work/SKILL.md +8 -1
  217. package/kits/catalog.json +6 -0
  218. package/kits/knowledge/kit.json +35 -0
  219. package/kits/knowledge/providers/conformance/fixtures/git-repo/CONTEXT.md +12 -0
  220. package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/decisions/old-sprocket-shape.md +13 -0
  221. package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/decisions/sprocket-shape.md +14 -0
  222. package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/decisions/widget-format.md +14 -0
  223. package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/learnings/fixture-learning.md +7 -0
  224. package/kits/knowledge/providers/conformance/fixtures/work-item/issues.json +30 -0
  225. package/kits/knowledge/providers/conformance/suite.test.js +125 -0
  226. package/kits/knowledge/providers/git-repo/index.js +236 -0
  227. package/kits/knowledge/providers/health/health-pass.test.js +99 -0
  228. package/kits/knowledge/providers/health/index.js +153 -0
  229. package/kits/knowledge/providers/index.js +24 -0
  230. package/kits/knowledge/providers/lib/model.js +91 -0
  231. package/kits/knowledge/providers/lib/schema-validate.js +119 -0
  232. package/kits/knowledge/providers/markdown-vault/index.js +169 -0
  233. package/kits/knowledge/providers/work-item/index.js +204 -0
  234. package/kits/veritas-governance/adapter/readiness-to-trust-bundle.mjs +178 -0
  235. package/kits/veritas-governance/docs/README.md +75 -0
  236. package/kits/veritas-governance/fixtures/readiness/not-ready.readiness-report.json +4645 -0
  237. package/kits/veritas-governance/fixtures/readiness/ready.readiness-report.json +4403 -0
  238. package/kits/veritas-governance/flows/readiness-check.flow.json +35 -0
  239. package/kits/veritas-governance/kit.json +16 -0
  240. package/package.json +11 -5
  241. package/packaging/README.md +2 -2
  242. package/packaging/conformance/fixtures/config-protection--allow-read-state-json.json +20 -0
  243. package/packaging/conformance/fixtures/config-protection--block-write-state-json.json +20 -0
  244. package/packaging/conformance/fixtures/stop-goal-fit--block-bundle-disputed-claim.json +1 -1
  245. package/packaging/conformance/fixtures/stop-goal-fit--block-capture-contradicts-claimed-pass.json +1 -1
  246. package/packaging/manifest.json +9 -10
  247. package/schemas/assignment-provider-settings.schema.json +125 -0
  248. package/schemas/decision-record.schema.json +109 -0
  249. package/schemas/knowledge/edge.schema.json +54 -0
  250. package/schemas/knowledge/health-report.schema.json +45 -0
  251. package/schemas/knowledge/node.schema.json +49 -0
  252. package/schemas/knowledge/proposal.schema.json +53 -0
  253. package/schemas/workflow-evidence.schema.json +1 -1
  254. package/schemas/workflow-state.schema.json +5 -0
  255. package/scripts/README.md +8 -3
  256. package/scripts/check-content-boundary.cjs +1 -1
  257. package/scripts/check-decisions.cjs +356 -0
  258. package/scripts/ci/derive-claim-status.mjs +74 -0
  259. package/scripts/ci/trust-reconcile.js +957 -103
  260. package/scripts/git-status.sh +2 -2
  261. package/scripts/hooks/claude-telemetry-hook.js +37 -3
  262. package/scripts/hooks/codex-telemetry-hook.js +36 -2
  263. package/scripts/hooks/config-protection.js +102 -30
  264. package/scripts/hooks/evidence-capture.js +3 -3
  265. package/scripts/hooks/lib/actor-identity.js +368 -0
  266. package/scripts/hooks/lib/config-protection-remedies.js +69 -0
  267. package/scripts/hooks/lib/liveness-heartbeat.js +361 -0
  268. package/scripts/hooks/lib/liveness-policy.js +127 -0
  269. package/scripts/hooks/lib/liveness-read.js +105 -12
  270. package/scripts/hooks/lib/liveness-write.js +46 -0
  271. package/scripts/hooks/lib/local-artifact-paths.js +12 -6
  272. package/scripts/hooks/opencode-telemetry-hook.js +27 -1
  273. package/scripts/hooks/pi-telemetry-hook.js +27 -1
  274. package/scripts/hooks/stop-goal-fit.js +157 -26
  275. package/scripts/hooks/workflow-steering.js +77 -3
  276. package/scripts/install-codex-home.sh +138 -38
  277. package/scripts/statusline/flow-agents-statusline.js +2 -2
  278. package/src/cli/assignment-provider.ts +845 -0
  279. package/src/cli/console-learning-projection.ts +3 -2
  280. package/src/cli/effective-assignment-provider-settings.ts +112 -0
  281. package/src/cli/init.ts +101 -21
  282. package/src/cli/kit.ts +37 -6
  283. package/src/cli/public-api.test.mjs +58 -6
  284. package/src/cli/pull-work-provider.ts +1 -1
  285. package/src/cli/trust-bundle-policy-order.test.mjs +87 -0
  286. package/src/cli/usage-feedback.ts +3 -3
  287. package/src/cli/validate-hook-influence.ts +1 -0
  288. package/src/cli/validate-workflow-artifacts.ts +27 -7
  289. package/src/cli/veritas-readiness-adapter.test.mjs +267 -0
  290. package/src/cli/workflow-artifact-cleanup-audit.ts +35 -2
  291. package/src/cli/workflow-sidecar.ts +933 -168
  292. package/src/cli.ts +6 -0
  293. package/src/flow-kit/validate.ts +74 -1
  294. package/src/index.ts +6 -2
  295. package/src/lib/flow-resolver.ts +123 -55
  296. package/src/lib/local-artifact-root.ts +24 -5
  297. package/src/lib/workflow-learning-projection.ts +2 -2
  298. package/src/runtime-adapters.ts +61 -15
  299. package/src/tools/build-universal-bundles.ts +49 -16
  300. package/src/tools/generate-context-map.ts +10 -8
  301. package/src/tools/validate-source-tree.ts +24 -1
@@ -0,0 +1,204 @@
1
+ /**
2
+ * work-item knowledge-store provider (source/sink adapter, not storage).
3
+ *
4
+ * Maps a GitHub issue backlog into the typed graph so backlog hygiene becomes a
5
+ * knowledge-health pass:
6
+ * - issues -> `issue` nodes (state / labels / title).
7
+ * - flow-agents:work-item-metadata `blockers` -> `blocks` edges.
8
+ * - prose "blocked by #N" -> `blocks` edges; other #N refs -> `relates`.
9
+ *
10
+ * Reads via an INJECTABLE runner so tests drive it from recorded fixtures and
11
+ * never touch the real board. Write side is proposals-only: proposeWrite renders
12
+ * a draft issue comment / label change for an operator to file — it never calls
13
+ * a mutating gh command.
14
+ *
15
+ * @module providers/work-item
16
+ */
17
+
18
+ import { execFile } from "node:child_process";
19
+ import { node, edge, proposal, provenance } from "../lib/model.js";
20
+
21
+ const PROVIDER_ID = "work-item";
22
+
23
+ /** Default runner: shells out to `gh` (read-only list). */
24
+ function defaultRunner(args) {
25
+ return new Promise((resolve, reject) => {
26
+ execFile("gh", args, { maxBuffer: 32 * 1024 * 1024 }, (err, stdout, stderr) => {
27
+ if (err) return reject(new Error(`gh ${args.join(" ")} failed: ${stderr || err.message}`));
28
+ resolve(stdout);
29
+ });
30
+ });
31
+ }
32
+
33
+ /** Parse the flow-agents:work-item-metadata JSON block from an issue body. */
34
+ export function parseWorkItemMetadata(body) {
35
+ if (!body) return null;
36
+ const start = body.indexOf("flow-agents:work-item-metadata");
37
+ if (start === -1) return null;
38
+ const jsonStart = body.indexOf("{", start);
39
+ const end = body.indexOf("-->", jsonStart);
40
+ if (jsonStart === -1 || end === -1) return null;
41
+ try {
42
+ return JSON.parse(body.slice(jsonStart, end).trim());
43
+ } catch {
44
+ return null;
45
+ }
46
+ }
47
+
48
+ /** Extract a blocker issue number from a metadata blocker entry. */
49
+ function blockerNumber(entry) {
50
+ if (typeof entry === "number") return entry;
51
+ if (typeof entry === "string") {
52
+ const m = entry.match(/#?(\d+)/);
53
+ return m ? Number(m[1]) : null;
54
+ }
55
+ if (entry && typeof entry === "object") {
56
+ if (typeof entry.number === "number") return entry.number;
57
+ if (typeof entry.issue === "number") return entry.issue;
58
+ if (typeof entry.ref === "string") {
59
+ const m = entry.ref.match(/#?(\d+)/);
60
+ return m ? Number(m[1]) : null;
61
+ }
62
+ }
63
+ return null;
64
+ }
65
+
66
+ export class WorkItemProvider {
67
+ constructor({ repo, runner, agent } = {}) {
68
+ this.repo = repo || "";
69
+ this.runner = runner || defaultRunner;
70
+ this.agent = agent;
71
+ this.id = PROVIDER_ID;
72
+ this._cache = null;
73
+ }
74
+
75
+ capabilities() {
76
+ return {
77
+ id: PROVIDER_ID,
78
+ node_types: ["issue"],
79
+ edge_types: ["blocks", "relates"],
80
+ writable: false,
81
+ write_mode: "proposals-only",
82
+ proposal_targets: ["comment", "label"],
83
+ source_of_truth: "GitHub issues (read via gh; write = draft comments/labels)",
84
+ };
85
+ }
86
+
87
+ async _issues() {
88
+ if (this._cache) return this._cache;
89
+ const args = ["issue", "list"];
90
+ if (this.repo) args.push("--repo", this.repo);
91
+ args.push("--state", "all", "--json", "number,title,state,labels,body", "--limit", "200");
92
+ const out = await this.runner(args);
93
+ const parsed = JSON.parse(out);
94
+ this._cache = Array.isArray(parsed) ? parsed : [];
95
+ return this._cache;
96
+ }
97
+
98
+ async readNodes(options = {}) {
99
+ const issues = await this._issues();
100
+ const now = new Date().toISOString();
101
+ const nodes = issues.map((iss) =>
102
+ node({
103
+ id: `issue:${iss.number}`,
104
+ type: "issue",
105
+ title: iss.title || `issue #${iss.number}`,
106
+ body: iss.body || "",
107
+ attributes: {
108
+ number: iss.number,
109
+ state: iss.state || "OPEN",
110
+ labels: (iss.labels || []).map((l) => (typeof l === "string" ? l : l.name)),
111
+ },
112
+ provenance: provenance({
113
+ provider: PROVIDER_ID,
114
+ source: this.repo ? `${this.repo}#${iss.number}` : `#${iss.number}`,
115
+ retrievedAt: now,
116
+ agent: this.agent,
117
+ }),
118
+ }),
119
+ );
120
+ if (options.type) return nodes.filter((n) => n.type === options.type);
121
+ return nodes;
122
+ }
123
+
124
+ async readEdges() {
125
+ const issues = await this._issues();
126
+ const now = new Date().toISOString();
127
+ const edges = [];
128
+ const seen = new Set();
129
+ const push = (e) => {
130
+ if (seen.has(e.id)) return;
131
+ seen.add(e.id);
132
+ edges.push(e);
133
+ };
134
+
135
+ for (const iss of issues) {
136
+ const self = `issue:${iss.number}`;
137
+ const prov = (loc) => provenance({ provider: PROVIDER_ID, source: this.repo ? `${this.repo}#${iss.number}` : `#${iss.number}`, locator: loc, retrievedAt: now, agent: this.agent });
138
+
139
+ // metadata blockers -> blocks (blocker blocks this)
140
+ const md = parseWorkItemMetadata(iss.body);
141
+ for (const b of (md && Array.isArray(md.blockers) ? md.blockers : [])) {
142
+ const n = blockerNumber(b);
143
+ if (n == null) continue;
144
+ push(edge({ id: `issue:${n}--blocks--${iss.number}`, type: "blocks", from: `issue:${n}`, to: self, attributes: { origin: "metadata" }, provenance: prov("metadata.blockers") }));
145
+ }
146
+
147
+ const body = iss.body || "";
148
+ // prose "blocked by #N" / "depends on #N" -> blocks
149
+ for (const m of body.matchAll(/\b(?:blocked by|depends on|blocker:)\s*#(\d+)/gi)) {
150
+ const n = Number(m[1]);
151
+ push(edge({ id: `issue:${n}--blocks--${iss.number}`, type: "blocks", from: `issue:${n}`, to: self, attributes: { origin: "prose" }, provenance: prov("body.prose") }));
152
+ }
153
+ // other bare #N prose refs -> relates
154
+ for (const m of body.matchAll(/(?<![\w/])#(\d+)\b/g)) {
155
+ const n = Number(m[1]);
156
+ if (n === iss.number) continue;
157
+ const bid = `issue:${iss.number}--relates--${n}`;
158
+ if (seen.has(`issue:${n}--blocks--${iss.number}`)) continue; // already a stronger blocks edge
159
+ push(edge({ id: bid, type: "relates", from: self, to: `issue:${n}`, attributes: { origin: "prose" }, provenance: prov("body.prose") }));
160
+ }
161
+ }
162
+ return edges;
163
+ }
164
+
165
+ async queryByType(type) {
166
+ return this.readNodes({ type });
167
+ }
168
+
169
+ async readGraph() {
170
+ const [nodes, edges] = await Promise.all([this.readNodes(), this.readEdges()]);
171
+ return { nodes, edges };
172
+ }
173
+
174
+ /**
175
+ * Propose an issue comment or label change. Renders the draft an operator
176
+ * would file with gh — the provider never runs a mutating gh command.
177
+ */
178
+ async proposeWrite(intent = {}) {
179
+ const { issue, kind = "comment", commentBody, labels = [] } = intent;
180
+ if (issue == null) throw new Error("work-item proposeWrite requires intent.issue (number)");
181
+ if (kind === "label") {
182
+ return proposal({
183
+ provider: PROVIDER_ID,
184
+ kind: "label",
185
+ target: { repo: this.repo, issue },
186
+ payload: { labels },
187
+ rendered: `gh issue edit ${issue}${this.repo ? ` --repo ${this.repo}` : ""} ${labels.map((l) => `--add-label ${JSON.stringify(l)}`).join(" ")}`,
188
+ rationale: intent.rationale || "Proposed label change (draft — operator files it).",
189
+ provenance: provenance({ provider: PROVIDER_ID, source: this.repo ? `${this.repo}#${issue}` : `#${issue}`, agent: this.agent }),
190
+ });
191
+ }
192
+ return proposal({
193
+ provider: PROVIDER_ID,
194
+ kind: "comment",
195
+ target: { repo: this.repo, issue },
196
+ payload: { body: commentBody || "" },
197
+ rendered: `gh issue comment ${issue}${this.repo ? ` --repo ${this.repo}` : ""} --body ${JSON.stringify(commentBody || "")}`,
198
+ rationale: intent.rationale || "Proposed issue comment (draft — operator files it).",
199
+ provenance: provenance({ provider: PROVIDER_ID, source: this.repo ? `${this.repo}#${issue}` : `#${issue}`, agent: this.agent }),
200
+ });
201
+ }
202
+ }
203
+
204
+ export default WorkItemProvider;
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env node
2
+ // readiness-to-trust-bundle.mjs — Veritas Governance Kit adapter (slice 1).
3
+ //
4
+ // PURPOSE (the "trust-bundle format gap" fix, kept in the KIT adapter layer — NOT in
5
+ // @kontourai/veritas). `veritas readiness --check evidence --working-tree` writes a legacy
6
+ // evidence-report record (`.kontourai/veritas/evidence/veritas-<runId>.json`). The Flow gate
7
+ // in flows/readiness-check.flow.json expects `kind: "trust.bundle"` — a Hachure trust.bundle
8
+ // carrying a `software-readiness-verdict` claim whose Surface-derived status the gate checks.
9
+ // This adapter projects Veritas's own recorded readiness record into that trust.bundle using
10
+ // @kontourai/surface (the same open-format bundle vocabulary Flow Agents' own delivery bundle
11
+ // and kits/builder/flows/build.flow.json use). It does NOT re-evaluate Repo Standards — Veritas
12
+ // already did that; the adapter only reads Veritas's recorded per-check results and aggregates
13
+ // the blocking-failure signal, so no Veritas rule/claim logic is forked or reimplemented.
14
+ //
15
+ // BLOCKING-FAILURE definition (SETTLED — owner-ratified + investigation-confirmed, see
16
+ // .kontourai/flow-agents/ws5-governance-kit-slice1 session findings). This adapter derives the
17
+ // readiness gate verdict from the readiness record's blocking failures: a Require-enforcement
18
+ // policy failure, an uncovered-path `fail`, a failed selected evidence check, or a blocking
19
+ // external-tool `fail`/`missing` (mirrors veritas/src/surface/readiness.mjs's own PRIVATE
20
+ // `readinessHasBlockingFailure` helper, and matches Surface's `buildTrustReport` weakest-link
21
+ // derivation, which downgrades a readiness claim to `rejected` on any rejected Require —
22
+ // tests/surface/readiness-derived-claim.test.mjs:256-278). It intentionally does NOT apply
23
+ // Veritas's EXPORTED `promotion_allowed` short-circuit (readinessSurfaceStatus/readinessVerdict
24
+ // treat promotion_allowed===true as verified/ready regardless of blocking Require failures):
25
+ // promotion_allowed is a workstream-routing hint from src/repo/routing.mjs `resolveWorkstream()`
26
+ // (file-pattern lane resolution), not a safety signal — it never reads policy_results, evidence
27
+ // checks, uncovered paths, or external tools, so it cannot account for blocking failures. This is
28
+ // a filed Veritas bug, not a legitimate alternate reading: kontourai/veritas#106
29
+ // (https://github.com/kontourai/veritas/issues/106) — "promotion_allowed short-circuit bypasses
30
+ // blocking Require failures" — recommends veritas fix readiness.mjs to check
31
+ // readinessHasBlockingFailure() before the promotion_allowed short-circuit. Conclusion: the
32
+ // adapter's stricter derivation is correct today and will agree with veritas's own exported
33
+ // functions once #106 lands; it is not a fork of Veritas's intended semantics, and the
34
+ // Governance Kit's blocking-failure semantics are the successor the wider system is moving
35
+ // toward (this adapter's independent CLI wrap was for reversibility while that landed). Ready
36
+ // (no blocking failure) -> Surface derives `verified` -> gate passes. Not-ready -> Surface
37
+ // derives a non-`verified` status -> gate blocks.
38
+ //
39
+ // Usage: node readiness-to-trust-bundle.mjs --report <veritas-evidence-report.json> \
40
+ // --out <bundle.json> [--subject-id <id>]
41
+ // Exit: 0 on success (bundle written), 2 on bad args, 3 on unreadable/invalid report.
42
+
43
+ import { readFileSync, writeFileSync } from "node:fs";
44
+ import * as surface from "@kontourai/surface";
45
+
46
+ function parseArgs(argv) {
47
+ const out = {};
48
+ for (let i = 0; i < argv.length; i++) {
49
+ const a = argv[i];
50
+ if (a === "--report") out.report = argv[++i];
51
+ else if (a === "--out") out.out = argv[++i];
52
+ else if (a === "--subject-id") out.subjectId = argv[++i];
53
+ }
54
+ return out;
55
+ }
56
+
57
+ // Mirrors veritas/src/surface/readiness.mjs's PRIVATE readinessHasBlockingFailure — reads
58
+ // Veritas's OWN recorded results; does not evaluate standards. Does NOT apply promotion_allowed
59
+ // (see header comment above): that short-circuit is a filed veritas bug (kontourai/veritas#106),
60
+ // not a safety signal — this stricter derivation is the settled-correct semantics.
61
+ export function hasBlockingFailure(record) {
62
+ if (record.uncovered_path_result === "fail") return true;
63
+ if ((record.policy_results ?? []).some((r) => r.passed === false && r.enforcementLevel === "Require")) return true;
64
+ if ((record.selected_evidence_checks ?? []).some((c) => c.evidence_check_result?.passed === false)) return true;
65
+ if ((record.external_tool_results ?? []).some((r) => r.blocking !== false && ["fail", "missing"].includes(r.verdict))) return true;
66
+ return false;
67
+ }
68
+
69
+ export function buildReadinessTrustBundle(record, opts = {}) {
70
+ const { deriveClaimStatus, generateClaimId } = surface;
71
+ const ts = record.timestamp || new Date().toISOString();
72
+ const runId = record.run_id || "veritas-run";
73
+ const sourceRef = record.integrity?.sourceRef ?? record.source_ref ?? runId;
74
+ const subjectId = opts.subjectId || sourceRef;
75
+ const blocking = hasBlockingFailure(record);
76
+ const ready = !blocking;
77
+
78
+ const claimType = "software-readiness-verdict";
79
+ const surfaceName = "veritas.readiness";
80
+ const claimId = generateClaimId(subjectId, surfaceName, "mergeReadiness");
81
+ const evId = `ev:${claimId}`;
82
+ const evidenceType = "policy_rule"; // readiness is a governance/policy result (auditability)
83
+
84
+ const policy = {
85
+ id: `policy:${claimType}`,
86
+ claimType,
87
+ requiredEvidence: [evidenceType],
88
+ acceptanceCriteria: ["A verified Veritas readiness evidence event supports the readiness verdict."],
89
+ reviewAuthority: "system",
90
+ validityRule: { kind: "manual" },
91
+ stalenessTriggers: [],
92
+ conflictRules: [],
93
+ impactLevel: "high",
94
+ };
95
+
96
+ const failedRules = (record.policy_results ?? [])
97
+ .filter((r) => r.passed === false && r.enforcementLevel === "Require")
98
+ .map((r) => r.rule_id);
99
+ const failedChecks = (record.selected_evidence_checks ?? [])
100
+ .filter((c) => c.evidence_check_result?.passed === false)
101
+ .map((c) => c.id);
102
+ const summary = ready
103
+ ? `Veritas readiness verdict is ready (run ${runId}); no blocking requirements or evidence failed.`
104
+ : `Veritas readiness verdict is not ready (run ${runId}). Blocking: ${[...failedRules, ...failedChecks].join(", ") || record.uncovered_path_result}.`;
105
+
106
+ const evItem = {
107
+ id: evId,
108
+ claimId,
109
+ evidenceType,
110
+ method: "auditability",
111
+ sourceRef: `veritas:readiness:${runId}`,
112
+ excerptOrSummary: summary,
113
+ observedAt: ts,
114
+ collectedBy: "veritas-governance-kit/readiness-adapter",
115
+ passing: ready,
116
+ };
117
+ const evt = {
118
+ id: `evt:${claimId}`,
119
+ claimId,
120
+ status: ready ? "verified" : "disputed",
121
+ actor: "veritas-governance-kit/readiness-adapter",
122
+ method: "auditability",
123
+ evidenceIds: [evId],
124
+ createdAt: ts,
125
+ verifiedAt: ts,
126
+ };
127
+ const claim = {
128
+ id: claimId,
129
+ subjectType: "repository-change",
130
+ subjectId,
131
+ facet: surfaceName,
132
+ claimType,
133
+ fieldOrBehavior: "mergeReadiness",
134
+ value: { verdict: ready ? "ready" : "not-ready", sourceRef, blocking: { failedRequirements: failedRules, failedEvidenceChecks: failedChecks } },
135
+ createdAt: ts,
136
+ updatedAt: ts,
137
+ impactLevel: "high",
138
+ verificationPolicyId: policy.id,
139
+ currentIntegrityRef: sourceRef,
140
+ metadata: { producer: "veritas", source: "readiness", runId },
141
+ };
142
+ const { status } = deriveClaimStatus({ claim, evidence: [evItem], events: [evt], policies: [policy] });
143
+
144
+ return {
145
+ bundle: {
146
+ schemaVersion: 5,
147
+ source: "veritas-governance-kit/readiness-adapter",
148
+ claims: [{ ...claim, status }],
149
+ evidence: [evItem],
150
+ events: [evt],
151
+ policies: [policy],
152
+ },
153
+ verdict: ready ? "ready" : "not-ready",
154
+ derivedStatus: status,
155
+ };
156
+ }
157
+
158
+ function main() {
159
+ const args = parseArgs(process.argv.slice(2));
160
+ if (!args.report || !args.out) {
161
+ process.stderr.write("usage: readiness-to-trust-bundle.mjs --report <veritas-evidence-report.json> --out <bundle.json> [--subject-id <id>]\n");
162
+ return 2;
163
+ }
164
+ let record;
165
+ try {
166
+ record = JSON.parse(readFileSync(args.report, "utf8"));
167
+ } catch (err) {
168
+ process.stderr.write(`cannot read Veritas evidence report: ${err && err.message ? err.message : String(err)}\n`);
169
+ return 3;
170
+ }
171
+ const { bundle, verdict, derivedStatus } = buildReadinessTrustBundle(record, { subjectId: args.subjectId });
172
+ writeFileSync(args.out, `${JSON.stringify(bundle, null, 2)}\n`, "utf8");
173
+ process.stdout.write(`readiness verdict: ${verdict}; software-readiness-verdict claim status: ${derivedStatus}; bundle: ${args.out}\n`);
174
+ return 0;
175
+ }
176
+
177
+ const isEntry = process.argv[1] && import.meta.url === `file://${process.argv[1]}`;
178
+ if (isEntry) process.exitCode = main();
@@ -0,0 +1,75 @@
1
+ # Veritas Governance Kit
2
+
3
+ Turns a repo's **Veritas-governed Repo Standards** into deterministic, agentless **gate
4
+ evidence**. Slice 1 ships the thinnest useful surface: one flow, one gate, that gates a real
5
+ `veritas readiness` verdict.
6
+
7
+ This kit **wraps** [`@kontourai/veritas`](https://www.npmjs.com/package/@kontourai/veritas) via
8
+ CLI invocation plus a small kit-local trust.bundle adapter. It does **not** fork, vendor, or
9
+ reimplement Veritas's Repo Standards / evidence-check evaluation — Veritas evaluates; the kit
10
+ only projects Veritas's own recorded verdict into the Flow trust.bundle vocabulary.
11
+
12
+ ## What it contains
13
+
14
+ | Asset | Path | Purpose |
15
+ | --- | --- | --- |
16
+ | Flow | `flows/readiness-check.flow.json` | Single-gate agentless flow `readiness -> gate-check`. The gate requires a **verified** `software-readiness-verdict` trust.bundle claim. |
17
+ | Adapter | `adapter/readiness-to-trust-bundle.mjs` | Projects a `veritas readiness --check evidence --working-tree` evidence report into a Hachure `trust.bundle` (via `@kontourai/surface`), deriving the claim status from Veritas's own blocking-failure signal. |
18
+ | Fixtures | `fixtures/readiness/*.readiness-report.json` | Captured **real** Veritas readiness reports (a ready clean tree, and a not-ready tree with a required CLI artifact deleted) used by the eval. |
19
+
20
+ The gate uses provider-neutral Flow vocabulary (`kind: "trust.bundle"`, `bundle_claim`) — the
21
+ same vocabulary `kits/builder/flows/build.flow.json` uses. Veritas is simply the producer that
22
+ satisfies it. `claimType: "software-readiness-verdict"` is taken directly from Veritas's own
23
+ Surface projection (`veritas/src/surface/projected-claims.mjs`, surface `veritas.readiness`).
24
+
25
+ ## How to run the gate
26
+
27
+ ```bash
28
+ # 1. Produce a real Veritas readiness report for your change.
29
+ veritas readiness --check evidence --working-tree
30
+ # -> writes .kontourai/veritas/evidence/veritas-<runId>.json
31
+
32
+ # 2. Project that report into a trust.bundle.
33
+ node kits/veritas-governance/adapter/readiness-to-trust-bundle.mjs \
34
+ --report .kontourai/veritas/evidence/veritas-<runId>.json \
35
+ --out readiness.bundle
36
+
37
+ # 3. Gate it (agentless, CI-callable — @kontourai/flow >= 1.3).
38
+ flow init
39
+ flow start kits/veritas-governance/flows/readiness-check.flow.json --run-id readiness
40
+ flow attach-evidence readiness --gate gate-check-gate --file readiness.bundle --bundle
41
+ flow evaluate readiness --gate gate-check-gate --exit-code
42
+ # exit 0 when readiness is ready (claim verified); exit 1 (block) otherwise.
43
+ ```
44
+
45
+ ## Semantics
46
+
47
+ **Settled** (owner-ratified + investigation-confirmed; see
48
+ `.kontourai/flow-agents/ws5-governance-kit-slice1` session findings). The adapter derives the
49
+ readiness gate verdict from **blocking failures** in Veritas's own recorded results: a
50
+ `Require`-enforcement policy failure, an uncovered-path `fail`, a failed selected evidence check,
51
+ or a blocking external-tool `fail`/`missing` makes the verdict **not-ready** → the
52
+ `software-readiness-verdict` claim derives a non-`verified` status → the gate **blocks**. A ready
53
+ verdict derives `verified` → the gate **passes**.
54
+
55
+ This matches Veritas's own `readinessHasBlockingFailure` helper (`veritas/src/surface/readiness.mjs`)
56
+ and Surface's weakest-link claim derivation (`buildTrustReport` downgrades a readiness claim to
57
+ `rejected` on any rejected Require). The adapter intentionally does **not** apply Veritas's
58
+ `promotion_allowed` short-circuit — `promotion_allowed` is a workstream-routing hint (set by
59
+ file-pattern lane resolution in `src/repo/routing.mjs`), not a safety signal, and applying it as
60
+ one lets a record with blocking Require failures read as ready. That short-circuit is a filed
61
+ Veritas bug, [kontourai/veritas#106](https://github.com/kontourai/veritas/issues/106), not a
62
+ legitimate alternate reading. Investigation conclusion: the adapter's stricter blocking-failure
63
+ derivation is correct today and will agree with Veritas's own exported functions once #106 lands.
64
+
65
+ ## Trust status
66
+
67
+ Slice 1 ships **unverified** (like `kits/release-evidence`); it is not on the first-party
68
+ allowlist (`src/flow-kit/validate.ts` `FIRST_PARTY_KIT_IDS`). First-party promotion is an owner
69
+ decision deferred to a later slice (see the WS5 shaping's open decisions).
70
+
71
+ ## Not in slice 1
72
+
73
+ Skills (`consult-standards`, `governance-evidence`), the fuller `merge-readiness` flow, the
74
+ `standards-authoring` flow, and the `knowledge` dependency are later slices — see the WS5
75
+ backlog.