@kontourai/flow-agents 3.2.0 → 3.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 (281) hide show
  1. package/.github/workflows/add-to-project.yml +15 -0
  2. package/.github/workflows/ci.yml +173 -0
  3. package/CHANGELOG.md +54 -0
  4. package/CONTEXT.md +5 -1
  5. package/README.md +19 -8
  6. package/build/src/builder-flow-run-adapter.d.ts +80 -0
  7. package/build/src/builder-flow-run-adapter.js +241 -0
  8. package/build/src/builder-flow-runtime.d.ts +16 -0
  9. package/build/src/builder-flow-runtime.js +290 -0
  10. package/build/src/cli/assignment-provider.js +10 -1
  11. package/build/src/cli/builder-run.d.ts +1 -0
  12. package/build/src/cli/builder-run.js +27 -0
  13. package/build/src/cli/effective-backlog-settings.js +70 -2
  14. package/build/src/cli/init.d.ts +34 -0
  15. package/build/src/cli/init.js +341 -61
  16. package/build/src/cli/kit.js +55 -12
  17. package/build/src/cli/pull-work-provider.js +346 -5
  18. package/build/src/cli/skill-drift-check.d.ts +1 -0
  19. package/build/src/cli/skill-drift-check.js +165 -0
  20. package/build/src/cli/telemetry-doctor.d.ts +37 -0
  21. package/build/src/cli/telemetry-doctor.js +53 -6
  22. package/build/src/cli/validate-hook-influence.js +37 -7
  23. package/build/src/cli/workflow-artifact-cleanup-audit.js +418 -11
  24. package/build/src/cli/workflow-sidecar.d.ts +310 -1
  25. package/build/src/cli/workflow-sidecar.js +1914 -126
  26. package/build/src/cli.js +5 -0
  27. package/build/src/flow-kit/validate.d.ts +54 -34
  28. package/build/src/flow-kit/validate.js +237 -26
  29. package/build/src/index.d.ts +2 -0
  30. package/build/src/index.js +1 -0
  31. package/build/src/lib/console-connect-options.d.ts +97 -0
  32. package/build/src/lib/console-connect-options.js +199 -0
  33. package/build/src/lib/console-telemetry-validate.d.ts +49 -0
  34. package/build/src/lib/console-telemetry-validate.js +91 -0
  35. package/build/src/lib/flow-resolver.d.ts +54 -1
  36. package/build/src/lib/flow-resolver.js +112 -5
  37. package/build/src/lib/fs.d.ts +17 -0
  38. package/build/src/lib/fs.js +172 -0
  39. package/build/src/lib/local-artifact-root.d.ts +44 -1
  40. package/build/src/lib/local-artifact-root.js +131 -3
  41. package/build/src/runtime-adapters.d.ts +39 -3
  42. package/build/src/runtime-adapters.js +77 -31
  43. package/build/src/tools/build-universal-bundles.js +40 -2
  44. package/build/src/tools/codex-agent-routing.d.ts +2 -0
  45. package/build/src/tools/codex-agent-routing.js +49 -0
  46. package/build/src/tools/generate-context-map.js +1 -0
  47. package/build/src/tools/validate-source-tree.js +30 -3
  48. package/context/contracts/artifact-contract.md +16 -2
  49. package/context/scripts/hooks/lib/kit-catalog.js +235 -0
  50. package/context/scripts/hooks/lib/runnable-command.js +177 -0
  51. package/context/scripts/hooks/stop-goal-fit.js +278 -48
  52. package/context/scripts/hooks/workflow-steering.js +194 -22
  53. package/context/scripts/package.json +3 -0
  54. package/context/scripts/telemetry/install-console-config.sh +25 -4
  55. package/context/scripts/telemetry/lib/config.sh +102 -12
  56. package/context/scripts/telemetry/lib/pricing.sh +50 -0
  57. package/context/scripts/telemetry/lib/session.sh +3 -0
  58. package/context/scripts/telemetry/lib/transport.sh +87 -0
  59. package/context/scripts/telemetry/lib/usage.sh +205 -4
  60. package/context/scripts/telemetry/telemetry.conf +6 -0
  61. package/context/scripts/telemetry/telemetry.sh +48 -0
  62. package/context/settings/workspace-backlog-provider-settings.example.json +48 -0
  63. package/docs/agent-usage-feedback-loop.md +35 -0
  64. package/docs/architecture-engine-and-kits.md +110 -0
  65. package/docs/context-map.md +2 -0
  66. package/docs/coordination-guide.md +370 -0
  67. package/docs/decisions/agent-coordination.md +26 -9
  68. package/docs/decisions/embeddable-engine.md +152 -0
  69. package/docs/decisions/index.md +5 -3
  70. package/docs/decisions/trust-ledger-retention.md +88 -0
  71. package/docs/decisions/trust-reconcile.md +42 -9
  72. package/docs/decisions/workflow-enforcement.md +31 -9
  73. package/docs/fixture-ownership.md +6 -2
  74. package/docs/implementing-trust-reconciliation.md +129 -0
  75. package/docs/index.md +23 -9
  76. package/docs/integrations/flow-agents-console.md +275 -0
  77. package/docs/integrations/index.md +4 -0
  78. package/docs/kit-authoring-guide.md +52 -21
  79. package/docs/spec/builder-flow-runtime.md +80 -0
  80. package/docs/spec/runtime-hook-surface.md +45 -1
  81. package/docs/specs/economics-record-contract.md +270 -0
  82. package/docs/specs/harness-capability-matrix.md +74 -0
  83. package/docs/specs/learning-review-proposals-contract.md +340 -0
  84. package/docs/specs/routing-efficiency-review.md +59 -0
  85. package/docs/verifiable-trust.md +74 -25
  86. package/docs/workflow-artifact-lifecycle.md +38 -1
  87. package/docs/workflow-usage-guide.md +10 -0
  88. package/evals/acceptance/prove-capture-teeth.sh +132 -0
  89. package/evals/ci/antigaming-suite.sh +2 -0
  90. package/evals/ci/run-baseline.sh +78 -4
  91. package/evals/fixtures/economics/acceptance.json +12 -0
  92. package/evals/fixtures/economics/agents/tool-worker-1/events.jsonl +2 -0
  93. package/evals/fixtures/economics/agents/tool-worker-2/events.jsonl +2 -0
  94. package/evals/fixtures/economics/agents/tool-worker-3/events.jsonl +2 -0
  95. package/evals/fixtures/economics/agents/tool-worker-4/events.jsonl +1 -0
  96. package/evals/fixtures/economics/agents/tool-worker-5/events.jsonl +2 -0
  97. package/evals/fixtures/economics/critique.json +22 -0
  98. package/evals/fixtures/economics/expected-record.json +71 -0
  99. package/evals/fixtures/economics/session-usage-event.json +1 -0
  100. package/evals/fixtures/economics/state.json +11 -0
  101. package/evals/fixtures/economics/transcript.jsonl +3 -0
  102. package/evals/fixtures/hook-influence/cases.json +7 -7
  103. package/evals/fixtures/learning-review-proposals/balanced/economics.jsonl +6 -0
  104. package/evals/fixtures/learning-review-proposals/effect-follow-up/economics.jsonl +5 -0
  105. package/evals/fixtures/learning-review-proposals/effect-follow-up/sessions/task-lr-ef-1/trust.bundle +21 -0
  106. package/evals/fixtures/learning-review-proposals/effect-follow-up/sessions/task-lr-ef-2/trust.bundle +21 -0
  107. package/evals/fixtures/learning-review-proposals/effect-follow-up/sessions/task-lr-ef-3/trust.bundle +21 -0
  108. package/evals/fixtures/learning-review-proposals/effect-follow-up/sessions/task-lr-ef-4/trust.bundle +21 -0
  109. package/evals/fixtures/learning-review-proposals/effect-follow-up/sessions/task-lr-ef-5/trust.bundle +21 -0
  110. package/evals/fixtures/learning-review-proposals/pattern-present/economics.jsonl +6 -0
  111. package/evals/fixtures/learning-review-proposals/pattern-present/expected-aggregates.json +30 -0
  112. package/evals/fixtures/learning-review-proposals/pattern-present/expected-aggregates.md +66 -0
  113. package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-1/gate-review.inquiries.json +26 -0
  114. package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-1/trust.bundle +21 -0
  115. package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-2/gate-review.inquiries.json +26 -0
  116. package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-2/trust.bundle +21 -0
  117. package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-3/gate-review.inquiries.json +26 -0
  118. package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-3/trust.bundle +21 -0
  119. package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-4/gate-review.inquiries.json +26 -0
  120. package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-4/trust.bundle +21 -0
  121. package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-5/trust.bundle +21 -0
  122. package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-6/trust.bundle +21 -0
  123. package/evals/fixtures/learning-review-proposals/repeat-window/economics.jsonl +6 -0
  124. package/evals/fixtures/learning-review-proposals/under-threshold/economics.jsonl +3 -0
  125. package/evals/fixtures/reconcile-preflight/disputed-critique-unsuperseded.json +48 -0
  126. package/evals/fixtures/reconcile-preflight/standalone-disputed-session-local.json +59 -0
  127. package/evals/fixtures/telemetry/usage-transcript-sample.jsonl +4 -0
  128. package/evals/fixtures/trust-reconcile-exploits/mcp-degrade.json +42 -0
  129. package/evals/integration/test_builder_entry_enforcement.sh +241 -0
  130. package/evals/integration/test_builder_step_producers.sh +18 -10
  131. package/evals/integration/test_bundle_install.sh +172 -0
  132. package/evals/integration/test_checkpoint_signing.sh +10 -2
  133. package/evals/integration/test_ci_actor_identity.sh +221 -0
  134. package/evals/integration/test_console_tenant_isolation.sh +167 -0
  135. package/evals/integration/test_critique_supersession_roundtrip.sh +4 -1
  136. package/evals/integration/test_dual_emit_flow_step.sh +10 -4
  137. package/evals/integration/test_economics_record.sh +674 -0
  138. package/evals/integration/test_effective_backlog_settings.sh +1 -1
  139. package/evals/integration/test_evidence_capture_hook.sh +17 -2
  140. package/evals/integration/test_exemption_usage_review.sh +198 -0
  141. package/evals/integration/test_fixture_retirement_audit.sh +2 -2
  142. package/evals/integration/test_flow_kit_install_git.sh +83 -0
  143. package/evals/integration/test_flowdef_session_activation.sh +0 -1
  144. package/evals/integration/test_flowdef_session_history_preservation.sh +13 -3
  145. package/evals/integration/test_gate_lockdown.sh +7 -0
  146. package/evals/integration/test_gate_review_inquiry_records.sh +9 -1
  147. package/evals/integration/test_goal_fit_hook.sh +2031 -0
  148. package/evals/integration/test_hook_category_behaviors.sh +8 -1
  149. package/evals/integration/test_hook_influence_cases.sh +25 -1
  150. package/evals/integration/test_install_merge.sh +227 -2
  151. package/evals/integration/test_kit_conformance_levels.sh +6 -6
  152. package/evals/integration/test_learning_review_proposals.sh +329 -0
  153. package/evals/integration/test_liveness_conflict_injection.sh +26 -22
  154. package/evals/integration/test_liveness_console_relay.sh +166 -0
  155. package/evals/integration/test_liveness_heartbeat.sh +17 -17
  156. package/evals/integration/test_liveness_worktree_root.sh +575 -0
  157. package/evals/integration/test_phase_map_and_gate_claim.sh +6 -1
  158. package/evals/integration/test_publish_delivery.sh +389 -2
  159. package/evals/integration/test_pull_work_board.sh +200 -0
  160. package/evals/integration/test_pull_work_provider.sh +1 -1
  161. package/evals/integration/test_reconcile_preflight.sh +304 -0
  162. package/evals/integration/test_record_check.sh +378 -0
  163. package/evals/integration/test_routing_efficiency.sh +71 -0
  164. package/evals/integration/test_runtime_adapter_activation.sh +28 -0
  165. package/evals/integration/test_session_resume_roundtrip.sh +16 -19
  166. package/evals/integration/test_skill_drift_check.sh +870 -0
  167. package/evals/integration/test_takeover_protocol.sh +340 -0
  168. package/evals/integration/test_telemetry.sh +445 -0
  169. package/evals/integration/test_telemetry_doctor.sh +66 -0
  170. package/evals/integration/test_telemetry_usage_pipeline.sh +228 -0
  171. package/evals/integration/test_trust_reconcile_negatives.sh +121 -13
  172. package/evals/integration/test_trust_reconcile_trailer_diagnostic.sh +247 -0
  173. package/evals/integration/test_usage_cost.sh +61 -0
  174. package/evals/integration/test_verify_hold.sh +910 -0
  175. package/evals/integration/test_veritas_governance_kit.sh +257 -0
  176. package/evals/integration/test_workflow_artifact_cleanup_audit.sh +575 -3
  177. package/evals/integration/test_workflow_sidecar_writer.sh +1395 -0
  178. package/evals/integration/test_workflow_steering_hook.sh +157 -16
  179. package/evals/integration/test_workspace_settings.sh +176 -0
  180. package/evals/lib/env.sh +26 -0
  181. package/evals/lib/node.sh +8 -0
  182. package/evals/run.sh +37 -0
  183. package/evals/static/test_ci_integration_coverage.sh +115 -0
  184. package/evals/static/test_declared_scope_forms_documented.sh +114 -0
  185. package/evals/static/test_universal_bundles.sh +34 -0
  186. package/evals/static/test_validate_source_kit_asset_scope.sh +259 -0
  187. package/evals/static/test_workflow_skills.sh +1 -1
  188. package/kits/builder/flows/build.flow.json +9 -18
  189. package/kits/builder/flows/publish-learn.flow.json +5 -1
  190. package/kits/builder/kit.json +120 -0
  191. package/kits/builder/skills/continue-work/SKILL.md +2 -0
  192. package/kits/builder/skills/deliver/SKILL.md +115 -0
  193. package/kits/builder/skills/evidence-gate/SKILL.md +12 -0
  194. package/kits/builder/skills/execute-plan/SKILL.md +9 -0
  195. package/kits/builder/skills/learning-review/SKILL.md +51 -0
  196. package/kits/builder/skills/plan-work/SKILL.md +17 -20
  197. package/kits/builder/skills/pull-work/SKILL.md +33 -2
  198. package/kits/builder/skills/release-readiness/SKILL.md +12 -0
  199. package/kits/knowledge/kit.json +9 -0
  200. package/kits/veritas-governance/docs/README.md +113 -7
  201. package/kits/veritas-governance/fixtures/exemption/approved.trust-bundle.json +74 -0
  202. package/kits/veritas-governance/fixtures/exemption/not-approved.trust-bundle.json +74 -0
  203. package/kits/veritas-governance/fixtures/exemption-review/mixed-fresh-stale.DECLARED.json +14 -0
  204. package/kits/veritas-governance/flows/exemption-issuance.flow.json +35 -0
  205. package/kits/veritas-governance/kit.json +19 -0
  206. package/kits/veritas-governance/skills/exemption-usage-review/SKILL.md +128 -0
  207. package/kits/veritas-governance/skills/exemption-usage-review/review-exemptions.mjs +231 -0
  208. package/package.json +2 -2
  209. package/packaging/manifest.json +29 -0
  210. package/schemas/backlog-provider-settings.schema.json +13 -0
  211. package/schemas/workflow-state.schema.json +44 -0
  212. package/scripts/README.md +4 -0
  213. package/scripts/check-content-boundary.cjs +8 -1
  214. package/scripts/ci/trust-reconcile.js +214 -253
  215. package/scripts/hooks/codex-hook-adapter.js +77 -2
  216. package/scripts/hooks/evidence-capture.js +38 -5
  217. package/scripts/hooks/lib/actor-identity.js +82 -0
  218. package/scripts/hooks/lib/codex-exit-code.js +316 -0
  219. package/scripts/hooks/lib/kit-catalog.js +235 -0
  220. package/scripts/hooks/lib/liveness-write.js +28 -1
  221. package/scripts/hooks/lib/local-artifact-paths.js +97 -1
  222. package/scripts/hooks/lib/runnable-command.js +177 -0
  223. package/scripts/hooks/lib/skill-drift.js +350 -0
  224. package/scripts/hooks/stop-goal-fit.js +278 -48
  225. package/scripts/hooks/workflow-steering.js +194 -22
  226. package/scripts/install-codex-home.sh +97 -47
  227. package/scripts/install-merge.js +72 -14
  228. package/scripts/install-owned-files.js +178 -0
  229. package/scripts/lib/reconcile-shape.js +381 -0
  230. package/scripts/liveness/relay.sh +84 -0
  231. package/scripts/telemetry/economics-record.schema.json +145 -0
  232. package/scripts/telemetry/economics-record.sh +331 -0
  233. package/scripts/telemetry/install-console-config.sh +25 -4
  234. package/scripts/telemetry/learning-review-decide.sh +124 -0
  235. package/scripts/telemetry/learning-review-proposals.schema.json +161 -0
  236. package/scripts/telemetry/learning-review-proposals.sh +484 -0
  237. package/scripts/telemetry/lib/config.sh +102 -12
  238. package/scripts/telemetry/lib/pricing.sh +14 -6
  239. package/scripts/telemetry/lib/session.sh +3 -0
  240. package/scripts/telemetry/lib/transport.sh +133 -15
  241. package/scripts/telemetry/lib/usage.sh +121 -28
  242. package/scripts/telemetry/routing-efficiency.sh +0 -0
  243. package/scripts/telemetry/telemetry.conf +6 -0
  244. package/scripts/telemetry/telemetry.sh +48 -0
  245. package/src/builder-flow-run-adapter.ts +357 -0
  246. package/src/builder-flow-runtime.ts +348 -0
  247. package/src/cli/assignment-provider.ts +12 -1
  248. package/src/cli/builder-flow-run-adapter.test.mjs +495 -0
  249. package/src/cli/builder-flow-runtime.test.mjs +213 -0
  250. package/src/cli/builder-run.ts +28 -0
  251. package/src/cli/codex-agent-routing.test.mjs +44 -0
  252. package/src/cli/codex-exit-code.test.mjs +207 -0
  253. package/src/cli/console-connect-options.test.mjs +329 -0
  254. package/src/cli/console-telemetry-validate.test.mjs +157 -0
  255. package/src/cli/effective-backlog-settings.ts +68 -2
  256. package/src/cli/flow-resolver-composition.test.mjs +72 -0
  257. package/src/cli/init.test.mjs +161 -0
  258. package/src/cli/init.ts +407 -62
  259. package/src/cli/kit-metadata-security.test.mjs +443 -0
  260. package/src/cli/kit.ts +50 -12
  261. package/src/cli/pull-work-provider.ts +377 -3
  262. package/src/cli/sidecar-pure-helpers.test.mjs +64 -0
  263. package/src/cli/skill-drift-check.ts +196 -0
  264. package/src/cli/telemetry-doctor.test.mjs +53 -0
  265. package/src/cli/telemetry-doctor.ts +50 -7
  266. package/src/cli/validate-hook-influence.ts +37 -6
  267. package/src/cli/workflow-artifact-cleanup-audit.ts +483 -10
  268. package/src/cli/workflow-sidecar.ts +1980 -119
  269. package/src/cli.ts +5 -0
  270. package/src/flow-kit/validate.ts +277 -38
  271. package/src/index.ts +19 -0
  272. package/src/lib/console-connect-options.ts +261 -0
  273. package/src/lib/console-telemetry-validate.ts +88 -0
  274. package/src/lib/flow-resolver.ts +117 -4
  275. package/src/lib/fs.ts +160 -0
  276. package/src/lib/local-artifact-root.ts +129 -3
  277. package/src/runtime-adapters.ts +113 -33
  278. package/src/tools/build-universal-bundles.ts +36 -2
  279. package/src/tools/codex-agent-routing.ts +48 -0
  280. package/src/tools/generate-context-map.ts +1 -0
  281. package/src/tools/validate-source-tree.ts +29 -3
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { type EffectiveState } from "./assignment-provider.js";
2
3
  type AnyObj = Record<string, any>;
3
4
  export declare const statuses: Set<string>;
4
5
  export declare const phases: string[];
@@ -132,6 +133,36 @@ type SurfaceModule = {
132
133
  assuranceLevel: "signed";
133
134
  } | null>;
134
135
  };
136
+ /**
137
+ * Fold a raw command-log (command-log.jsonl entries) into a per-command classification,
138
+ * keyed by normalized command text (whitespace-collapsed, trimmed). Pure and side-effect-free
139
+ * so it is directly unit-testable (#470 iteration 2, finding #2 — HIGH: the prior inline reducer
140
+ * collapsed every non-"fail" `observedResult` — including "ambiguous" — to "pass", feeding a
141
+ * verified event + `passing:true` and reintroducing the #470 false-pass through the trust-bundle
142
+ * reconciliation path).
143
+ *
144
+ * Three-way classification, keyed on `observedResult` (never re-derived from `exitCode` alone,
145
+ * which would miscoerce the #362 grep/diff absence carve-out `ambiguous,exitCode:1` entry to
146
+ * `fail`):
147
+ * - "fail" when `observedResult==="fail"`, or (legacy, no observedResult) a nonzero
148
+ * integer `exitCode`.
149
+ * - "ambiguous" when `observedResult==="ambiguous"`, or (legacy) `exitCode` is `null` with no
150
+ * fail signal.
151
+ * - "pass" when `observedResult==="pass"`, or (legacy) `exitCode===0`.
152
+ *
153
+ * Precedence across repeated entries for the same command: fail > pass > ambiguous. A genuine
154
+ * exit-0 pass is positive evidence and confirms; ambiguous holds only when there is neither a
155
+ * fail nor a positive pass, since a "pass" always requires positive evidence.
156
+ *
157
+ * The caller (buildTrustBundle) maps "ambiguous" onto the existing canonical non-confirming
158
+ * status `not_verified` — consume-never-fork, mirroring record-check's identical mapping — so
159
+ * `checkStatusToEventStatus("not_verified")` returns null (no verification event emitted) and the
160
+ * evidence item is stamped `passing:false`. See Decision/finding #2 in the iteration-2 plan.
161
+ */
162
+ export declare function reduceCaptureLogByCommand(commandLog: AnyObj[] | undefined): Map<string, {
163
+ observedResult: "pass" | "fail" | "ambiguous";
164
+ exitCode: number | null;
165
+ }>;
135
166
  /**
136
167
  * Build a Hachure trust.bundle from raw check/criterion/critique inputs.
137
168
  * trust.bundle is the PRIMARY artifact (ADR 0010 Phase 4a producer inversion).
@@ -166,7 +197,7 @@ export declare function writeTrustBundle(dir: string, slug: string, timestamp: s
166
197
  export declare function sidecarBase(slug: string): AnyObj;
167
198
  export declare function validateEvidenceRef(ref: AnyObj, label: string): AnyObj;
168
199
  export declare function normalizeEvidenceRefs(raw: unknown, label: string): AnyObj[];
169
- export declare function normalizeCheck(raw: AnyObj): AnyObj;
200
+ export declare function normalizeCheck(raw: AnyObj, allowGateClaimPrefix?: boolean, existingCheckStampById?: ReadonlyMap<string, boolean>): AnyObj;
170
201
  /**
171
202
  * Derive kit identity from a parsed trust.bundle by structurally reading the
172
203
  * DECLARED primary claim (kit-typed) rather than hardcoding "builder".
@@ -201,6 +232,235 @@ export declare function normalizeFinding(raw: AnyObj): AnyObj;
201
232
  * Signing is ALWAYS fail-open — a signing failure never breaks the seal.
202
233
  */
203
234
  export declare function sealTrustCheckpoint(dir: string, slug: string, sealedAt: string, status: string, phase: string): Promise<void>;
235
+ /**
236
+ * Distinct, identifiable error for a shape-invalid trust.bundle — NOT a generic Error, so
237
+ * every publishDelivery() call site (advanceState/recordRelease/promote/publishDeliveryCmd)
238
+ * can positively distinguish "refuses to publish an invalid bundle" (must be LOUD, fail
239
+ * closed, AC6) from the other failure modes those call sites already tolerate as best-effort
240
+ * (missing kits/ ancestor for a scratch dir, I/O errors, etc — see each catch's own comment).
241
+ * A bare `instanceof Error` check would not suffice since every thrown failure in this file is
242
+ * already an Error; `code` is the recognizable, grep-stable discriminator.
243
+ */
244
+ export declare class InvalidBundleShapeError extends Error {
245
+ readonly code: "RECONCILE_PREFLIGHT_INVALID_SHAPE";
246
+ readonly issues: string[];
247
+ constructor(issues: string[]);
248
+ }
249
+ /**
250
+ * Distinct, identifiable error for a publish attempt by an actor who is NOT the fresh,
251
+ * non-superseded holder of the subject (issue #293, ADR 0021 §3) — NOT a generic Error and NOT
252
+ * `InvalidBundleShapeError` (#356), so every publishDelivery() call site can positively
253
+ * distinguish "refuses to publish because the bundle shape is invalid" from "refuses to publish
254
+ * because this actor no longer holds the subject" — two genuinely distinct fail-closed tiers
255
+ * that must never be conflated in a catch handler (a worker fixing a shape issue must not be
256
+ * told to "re-record evidence" when the real problem is a stale/superseded claim, and vice
257
+ * versa). Mirrors `InvalidBundleShapeError`'s shape exactly: same `extends Error` base, same
258
+ * `readonly code` discriminator convention, same doc-comment structure — only the payload
259
+ * differs (the effective-state/holder/reason/guidance `runVerifyHold()` computed, rather than a
260
+ * shape-issue list).
261
+ */
262
+ export declare class NotFreshHolderError extends Error {
263
+ readonly code: "VERIFY_HOLD_NOT_FRESH_HOLDER";
264
+ readonly effective_state: EffectiveState | "not_evaluated";
265
+ readonly holder?: {
266
+ actor?: string;
267
+ assignee?: string | null;
268
+ idle_days?: number | null;
269
+ last_at?: string;
270
+ };
271
+ readonly reason: string;
272
+ readonly guidance: string[];
273
+ constructor(result: {
274
+ effective_state: EffectiveState | "not_evaluated";
275
+ holder?: {
276
+ actor?: string;
277
+ assignee?: string | null;
278
+ idle_days?: number | null;
279
+ last_at?: string;
280
+ };
281
+ reason: string;
282
+ guidance: string[];
283
+ });
284
+ }
285
+ /**
286
+ * Distinct, identifiable error for a publish attempt whose resolved `repoRoot` does not
287
+ * positively confirm the session's sealed `trust.checkpoint.json` `commit_sha` — a FOURTH,
288
+ * distinct fail-closed tier (#413 Facet A), never conflated with `InvalidBundleShapeError`
289
+ * (bundle shape) or `NotFreshHolderError` (actor hold). This is the "refuse loudly when the cwd
290
+ * repo does not match the sealed checkpoint commit_sha" fallback the issue itself proposed:
291
+ * `publishDelivery`'s `repoRoot` is resolved by walking up from the ARTIFACT directory
292
+ * (findRepoRootFromDirStrict), which always physically lives under the primary checkout even
293
+ * when invoked from an unrelated worktree/repo — so a positively-confirmed mismatch here is the
294
+ * signal that this resolved repoRoot is NOT the repo the sealed checkpoint was produced against,
295
+ * and publishing into it would silently write to the wrong tree.
296
+ *
297
+ * #413 iteration-2 Fix 4: thrown for the ONE positively-determinable `mismatchKind` (see
298
+ * checkpointHeadAncestry's doc comment) — `"positive"` (repoRoot's HEAD is confirmed NOT an
299
+ * ancestor-or-equal of commit_sha; `headSha` is a real sha). It is intentionally NEVER thrown for
300
+ * `"undeterminable-shallow"` (e.g. a shallow clone missing the commit object) — that case only
301
+ * warns and allows the publish (see publishDelivery's own gate). A non-git `repoRoot` classifies
302
+ * as `mismatchKind === "none"` (no opinion — allow; see checkpointHeadAncestry's doc comment for
303
+ * why the iteration-2 Fix 5 refusal here was reverted in iteration-3) and never throws this error
304
+ * either.
305
+ */
306
+ export declare class RepoHeadMismatchError extends Error {
307
+ readonly code: "PUBLISH_DELIVERY_REPO_HEAD_MISMATCH";
308
+ readonly repoRoot: string;
309
+ readonly commitSha: string;
310
+ readonly headSha: string;
311
+ constructor(repoRoot: string, commitSha: string, headSha: string);
312
+ }
313
+ export declare function runReconcilePreflight(dir: string, repoRoot: string, manifestOverride?: string | null): {
314
+ ok: boolean;
315
+ issues: string[];
316
+ warnings: string[];
317
+ };
318
+ /**
319
+ * The ONE hard-stop gate (issue #293, ADR 0021 §3): "is my actor the fresh, non-superseded
320
+ * holder of this subject (or is the subject free/self-held)?" Reuses the SAME assignment ⋈
321
+ * liveness join #290/#291 already built (`computeEffectiveState` + `readLocalAssignmentStatus`
322
+ * + `readLivenessEvents`/`freshHolders`) — no second computation is invented here. This is the
323
+ * mirror-image check, at the OTHER end of the session lifecycle, of
324
+ * `enforceEnsureSessionOwnership`'s pre-entry guard above: that guard decides whether entry
325
+ * should claim/supersede/refuse; this gate decides whether PUBLISH should proceed, with a
326
+ * different (new) per-effective-state mapping — the ownership guard's "claim"/"supersede"
327
+ * actions are wrong at publish time, so this is new interpretation of the existing join output,
328
+ * not a new join and not a new `EffectiveState` value (there is no literal `"superseded"` state
329
+ * — a superseded-away actor's own re-check naturally resolves to `held`(holder=successor) or
330
+ * `reclaimable`, never `self_is_holder`; see assignment-provider.ts's `computeEffectiveState`).
331
+ *
332
+ * Effective-state -> publish-decision mapping (the operative spec, from the plan's table).
333
+ * IMPORTANT (bug fix, #397): this gate fences the durable ASSIGNMENT hold, not ambient
334
+ * liveness — liveness is advisory everywhere else in the system, and this is the ONE hard
335
+ * gate, so it must never false-block on liveness alone. A subject with fresh liveness by
336
+ * another actor but NO durable assignment record (`held`, reason
337
+ * `liveness_claim_present_assignment_lagging`) therefore PASSES, not BLOCKs — there is no
338
+ * durable ownership conflict to protect, only ambient presence. This does NOT weaken zombie
339
+ * protection: a superseded zombie always has an assignment record (either its own stale
340
+ * assignment — `reclaimable` — or the successor's assignment-backed `held`/
341
+ * `fresh_liveness_heartbeat`), both of which still BLOCK below.
342
+ * - `free` (no assignment ever recorded) -> PASS (never false-block an untracked subject)
343
+ * - `held`, reason `self_is_holder` -> PASS (the caller IS the current holder)
344
+ * - `held`, reason `liveness_claim_present_assignment_lagging`
345
+ * (fresh liveness by another actor, NO durable assignment record) -> PASS (liveness alone
346
+ * is never a durable ownership conflict — see #397 fix note above)
347
+ * - `held`, reason `fresh_liveness_heartbeat`
348
+ * (durable assignment held by another actor + fresh liveness) -> BLOCK (a different
349
+ * actor durably holds this subject and is demonstrably still live)
350
+ * - `reclaimable` (assignment present, stale/absent liveness) -> BLOCK (not proof of
351
+ * self — safe default blocks; a durable assignment record exists)
352
+ * - `human-held` -> BLOCK (never publish over a human assignee)
353
+ * - no resolvable join at all (non-local-file provider
354
+ * with no --effective-state-json) -> `not_evaluated`, PASS (documented scope
355
+ * boundary, loud stderr note, never a silent block)
356
+ *
357
+ * Actor resolution mirrors `enforceEnsureSessionOwnership` EXACTLY: the bare
358
+ * `resolveActor(env).actor` / branchActorKey string, NEVER `serializeActor(actorStruct)`'s
359
+ * triple — the #291 flat-vs-triple seam. `opts.actorKey` (the CLI's --actor / FLOW_AGENTS_ACTOR
360
+ * override, already sanitized by the caller) takes precedence when provided.
361
+ *
362
+ * Slug/artifactRoot derivation matches `publishDelivery()`'s own `slug =
363
+ * path.basename(path.resolve(dir))` byte-for-byte (both must resolve the SAME assignment
364
+ * record) and the `artifactRoot = path.dirname(dir)` pattern already used elsewhere in this
365
+ * file for a `dir`-only consumer.
366
+ *
367
+ * github provider: read-only precomputed `--effective-state-json` escape hatch, matching
368
+ * `enforceEnsureSessionOwnership`'s existing github branch precedent exactly (render-don't-
369
+ * execute — assignment-provider.ts never calls `gh` directly from this CLI).
370
+ *
371
+ * Every interpolated actor/holder/reason string is sanitized via
372
+ * `stripControlCharsForDisplay(...).slice(0, 64)` — reusing the exact top-level helper, never a
373
+ * second sanitizer (AC7).
374
+ *
375
+ * SECOND CI-blocking false-block fix (this iteration): the hard gate above enforces ONLY for a
376
+ * STABLY-identified actor. A caller's identity is STABLE when it comes from an explicit
377
+ * `opts.actorKey` (a caller that hands in an actor key is asserting a stable identity — e.g. the
378
+ * CLI's --actor / FLOW_AGENTS_ACTOR override, or the github skill's precomputed path), from
379
+ * `FLOW_AGENTS_ACTOR` (`resolveActor` source `"explicit-override"`), or from a runtime-native
380
+ * session id (`resolveActor` source `` `runtime-session-id:${runtime}` ``, e.g. Claude Code's
381
+ * `CLAUDE_CODE_SESSION_ID`). It is UNSTABLE when `resolveActor` falls all the way through to the
382
+ * process-ancestry fallback (source `"process-ancestry"`) or fails to resolve at all (source
383
+ * `"unresolved"` / `isUnresolvedActor(actor)`). This mirrors `enforceEnsureSessionOwnership`'s
384
+ * Design Decision 4 (never hard-fail on actor ambiguity): a session that cannot stably
385
+ * self-identify cannot be meaningfully fenced against a durable assignment record, so hard-
386
+ * blocking it produces exactly the false-block CI hit (no `FLOW_AGENTS_ACTOR`/runtime session id
387
+ * in CI -> ancestry fallback -> a DIFFERENT ancestry-derived actor string than the one that
388
+ * created the claim -> `reclaimable`/not-self -> hard BLOCK of a legitimate self-publish). A
389
+ * real coordination participant always has a stable identity (explicit override or runtime
390
+ * session id), so zombie protection under a stable actor is completely unaffected — this only
391
+ * changes behavior for a caller that was never fenceable in the first place. When the resolved
392
+ * actor identity is UNSTABLE, this function short-circuits to `{ ok: true, effective_state:
393
+ * "not_evaluated", reason: "actor-identity-unstable-advisory-only" }` (holder included, sanitized,
394
+ * when one exists) BEFORE running the assignment ⋈ liveness join at all, with one loud stderr
395
+ * note — the gate degrades to advisory-only rather than ever false-blocking an unstable identity.
396
+ * When the actor identity IS stable, the effective-state -> publish-decision mapping above
397
+ * applies exactly as documented, unchanged.
398
+ */
399
+ export declare function runVerifyHold(dir: string, repoRoot: string | null, opts?: {
400
+ actorKey?: string;
401
+ now?: number;
402
+ assignmentProviderKind?: string;
403
+ effectiveStateJson?: unknown;
404
+ }): {
405
+ ok: boolean;
406
+ effective_state: EffectiveState | "not_evaluated";
407
+ holder?: {
408
+ actor?: string;
409
+ assignee?: string | null;
410
+ idle_days?: number | null;
411
+ last_at?: string;
412
+ };
413
+ reason: string;
414
+ guidance: string[];
415
+ };
416
+ /**
417
+ * Render (never execute) the takeover protocol for a candidate the skill has selected. Takeover is
418
+ * RESUMPTION, not restart: when a subject is `reclaimable` (a durable assignment whose incumbent is
419
+ * no longer heartbeating), a successor must (1) grace-beat — wait one heartbeat interval and re-check,
420
+ * backing off if the incumbent revives — (2) supersede via `ensure-session --supersede-stale`, and
421
+ * (3) CONTINUE THE INCUMBENT'S BRANCH (from the incumbent's claim record), never a parallel one, and
422
+ * re-enter the SAME artifact dir (deterministic slug). This function computes the effective state
423
+ * (the same assignment ⋈ liveness join verify-hold/ensure-session use) and emits the appropriate
424
+ * action + the incumbent's `resume_branch`; the skill executes the beat/supersede/git steps.
425
+ *
426
+ * Race-safety is CLI-enforced at supersede time, not here: `ensure-session --supersede-stale`
427
+ * re-computes the state and refuses (dies on `held`) if the incumbent revived during the beat, so a
428
+ * successor that skipped or lost the grace race still cannot supersede a live incumbent (AC2a).
429
+ *
430
+ * ADVISORY, not a gate: the assignment ⋈ liveness JOIN is identical to verify-hold's, but this render
431
+ * only advises the skill which action to take — the ACTUAL enforcement is `ensure-session
432
+ * --supersede-stale` (re-check under a subject lock). So it deliberately does NOT replicate
433
+ * verify-hold's #398 `isStableActor` tiering (which exists there only because verify-hold is a hard
434
+ * publish BLOCK that must not false-block an unstable/ancestry identity): a wrong self-identification
435
+ * here yields only a wrong advisory string, never a wrong mutation.
436
+ *
437
+ * Ordering note: ADR 0021 §5's literal wording is supersede→grace→maybe-undo; this implements
438
+ * grace→recheck→supersede (never write until the beat confirms the incumbent stayed stale) — a
439
+ * deliberate, safer variant that preserves the ADR's intent ("laptop just woke resolves in the
440
+ * incumbent's favor") without a premature write to walk back.
441
+ *
442
+ * All untrusted fields (incumbent actor / branch / last_at, sourced from the shared multi-writer
443
+ * assignment+liveness stream) pass through `sanitize`/`sanitizeWide` (stripControlCharsForDisplay +
444
+ * the repo's 64/240 cap tiers — branch uses the 240 free-text tier so a valid long branch is never
445
+ * truncated into a bad checkout target) — the #287/#320/#293 injection class.
446
+ */
447
+ export declare function runTakeoverPreflight(dir: string, opts?: {
448
+ actorKey?: string;
449
+ now?: number;
450
+ graceSeconds?: number;
451
+ }): {
452
+ ok: boolean;
453
+ action: "grace-then-supersede" | "back-off" | "claim" | "ask-first" | "proceed";
454
+ effective_state: EffectiveState;
455
+ reason: string;
456
+ holder?: {
457
+ actor?: string;
458
+ last_at?: string;
459
+ };
460
+ resume_branch?: string;
461
+ grace_seconds?: number;
462
+ next_steps: string[];
463
+ };
204
464
  /**
205
465
  * Publish the session's trust artifacts to the committed delivery/ path.
206
466
  *
@@ -226,6 +486,55 @@ export declare function sealTrustCheckpoint(dir: string, slug: string, sealedAt:
226
486
  * evals/integration/test_checkpoint_signing.sh TEST 2 and the WS5 session findings at
227
487
  * .kontourai/flow-agents/ws5-governance-kit-slice1 for the root cause this fixes).
228
488
  * Idempotent: overwrites on re-delivery to the same slug.
489
+ *
490
+ * #356 Wave 3 (AC6): Fail-CLOSED on bundle SHAPE. After the fail-soft absence guard below,
491
+ * runs the SAME reconcile-preflight shape check (runReconcilePreflight) the
492
+ * `reconcile-preflight` CLI subcommand exposes, BEFORE copying anything into delivery/. A
493
+ * shape-invalid bundle throws InvalidBundleShapeError (a distinct, identifiable error — see
494
+ * its own doc comment) rather than silently publishing a bundle CI's Trust Reconcile job
495
+ * would reject anyway. This is intentionally a NEW, additive fail-closed branch — it must
496
+ * never be conflated with the pre-existing fail-soft absence/repo-root branches above/below,
497
+ * which stay exactly as before (see each publishDelivery call site's catch handler for how
498
+ * the distinction is preserved end-to-end).
499
+ *
500
+ * #293 (THIRD, DISTINCT fail-closed gate): immediately after the shape check above and BEFORE
501
+ * writing anything into delivery/, runs `runVerifyHold()` — the assignment ⋈ liveness join
502
+ * asking "is the calling actor the fresh, non-superseded holder of this subject (or is it
503
+ * free/self-held)?" A not-fresh-holder result throws `NotFreshHolderError` (distinct from
504
+ * `InvalidBundleShapeError` — a different `code`, a different failure mode: actor hold vs
505
+ * bundle shape).
506
+ *
507
+ * #413 Facet A (FOURTH, DISTINCT fail-closed gate): immediately after the verify-hold gate and
508
+ * BEFORE writing anything into delivery/, compares the resolved `repoRoot`'s `git rev-parse
509
+ * HEAD` against the session's sealed `trust.checkpoint.json` `commit_sha` (via the shared
510
+ * checkpointHeadAncestry() helper — the SAME ancestor-check checkpointStalenessWarning already
511
+ * used as a non-blocking warning). Throws `RepoHeadMismatchError` (distinct from both other
512
+ * error tiers) instead of silently publishing into what is very likely the WRONG repo (e.g.
513
+ * `repoRoot` resolved to the primary checkout via findRepoRootFromDirStrict's artifact-dir
514
+ * walk, even though this session's checkpoint was sealed against a DIFFERENT worktree's HEAD).
515
+ * A session with no checkpoint yet, or a checkpoint with no commit_sha, has nothing to compare
516
+ * against and is unaffected (scoped strictly to the mismatch case, never a spurious refusal).
517
+ *
518
+ * #413 iteration-2 Fix 4 (see checkpointHeadAncestry's own doc comment for the full
519
+ * `mismatchKind` classification this gate reads): only `mismatchKind === "positive"` (a
520
+ * POSITIVELY-DETERMINABLE ancestry mismatch — the real wrong-tree harm case) hard refuses here.
521
+ * `"undeterminable-shallow"` (e.g. a local shallow clone missing the commit_sha object) must
522
+ * NEVER hard-refuse a legitimate publish — this branch only WARNS loudly and lets the shape +
523
+ * verify-hold gates above continue to stand guard. A non-git `repoRoot` classifies as
524
+ * `mismatchKind === "none"` (allow) — iteration-2's Fix 5 hard-refused this case too, but that
525
+ * regressed the SUPPORTED non-git-repoRoot scratch/checkpoint-signing flow (see
526
+ * evals/integration/test_checkpoint_signing.sh TEST 2) and was reverted in iteration-3. Wrong-tree
527
+ * protection for that case relies on the shape-check and verify-hold gates above, which correctly
528
+ * no-op (allow) when there is no git repo to inspect, same as this gate.
529
+ *
530
+ * There are now FOUR fail-closed/fail-soft TIERS in this function, and they must never be
531
+ * conflated in prose or in a call site's catch handler: (1) fail-SOFT bundle absence /
532
+ * repo-root resolution (silent no-op / visible warning, unchanged from before #356), (2)
533
+ * fail-CLOSED bundle shape (#356, `InvalidBundleShapeError`), (3) fail-CLOSED verify-hold (#293,
534
+ * `NotFreshHolderError`), (4) fail-CLOSED repo-HEAD-vs-checkpoint mismatch (#413 Facet A,
535
+ * `RepoHeadMismatchError`) — see this tier's own gate below for the undeterminable-shallow
536
+ * carve-out. Tiers run in this fixed order (shape, then verify-hold, then HEAD-mismatch); a
537
+ * bundle that fails an earlier tier throws that tier's error specifically, never a later one's.
229
538
  */
230
539
  export declare function publishDelivery(dir: string, repoRoot: string | null): Promise<void>;
231
540
  export declare function validateLearningCorrection(record: AnyObj): void;