@kontourai/flow-agents 3.11.0 → 3.12.1
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.
- package/CHANGELOG.md +14 -0
- package/build/src/builder-flow-run-adapter.d.ts +1 -0
- package/build/src/builder-flow-run-adapter.js +2 -0
- package/build/src/builder-flow-runtime.d.ts +5 -0
- package/build/src/builder-flow-runtime.js +90 -68
- package/build/src/builder-gate-action-envelope.d.ts +152 -0
- package/build/src/builder-gate-action-envelope.js +368 -0
- package/build/src/cli/public-contracts.d.ts +139 -0
- package/build/src/cli/public-contracts.js +37 -0
- package/build/src/cli/workflow-sidecar.js +9 -13
- package/build/src/cli/workflow.d.ts +1 -0
- package/build/src/cli/workflow.js +49 -12
- package/build/src/continuation-driver.d.ts +40 -3
- package/build/src/continuation-driver.js +361 -412
- package/build/src/continuation-persistence.d.ts +4 -0
- package/build/src/continuation-persistence.js +296 -0
- package/build/src/continuation-validation.d.ts +9 -0
- package/build/src/continuation-validation.js +169 -0
- package/build/src/flow-kit/action-metadata.d.ts +28 -0
- package/build/src/flow-kit/action-metadata.js +162 -0
- package/build/src/flow-kit/action-repository-validation.d.ts +16 -0
- package/build/src/flow-kit/action-repository-validation.js +237 -0
- package/build/src/flow-kit/validate.d.ts +2 -14
- package/build/src/flow-kit/validate.js +18 -345
- package/build/src/index.d.ts +4 -2
- package/build/src/index.js +2 -1
- package/dist/base/build/package.json +1 -1
- package/dist/base/build/src/builder-flow-run-adapter.d.ts +1 -0
- package/dist/base/build/src/builder-flow-run-adapter.js +2 -0
- package/dist/base/build/src/builder-flow-runtime.d.ts +5 -0
- package/dist/base/build/src/builder-flow-runtime.js +90 -68
- package/dist/base/build/src/builder-gate-action-envelope.d.ts +152 -0
- package/dist/base/build/src/builder-gate-action-envelope.js +368 -0
- package/dist/base/build/src/cli/public-contracts.d.ts +139 -0
- package/dist/base/build/src/cli/public-contracts.js +37 -0
- package/dist/base/build/src/cli/workflow-sidecar.js +9 -13
- package/dist/base/build/src/cli/workflow.d.ts +1 -0
- package/dist/base/build/src/cli/workflow.js +49 -12
- package/dist/base/build/src/continuation-driver.d.ts +40 -3
- package/dist/base/build/src/continuation-driver.js +361 -412
- package/dist/base/build/src/continuation-persistence.d.ts +4 -0
- package/dist/base/build/src/continuation-persistence.js +296 -0
- package/dist/base/build/src/continuation-validation.d.ts +9 -0
- package/dist/base/build/src/continuation-validation.js +169 -0
- package/dist/base/build/src/flow-kit/action-metadata.d.ts +28 -0
- package/dist/base/build/src/flow-kit/action-metadata.js +162 -0
- package/dist/base/build/src/flow-kit/action-repository-validation.d.ts +16 -0
- package/dist/base/build/src/flow-kit/action-repository-validation.js +237 -0
- package/dist/base/build/src/flow-kit/validate.d.ts +2 -14
- package/dist/base/build/src/flow-kit/validate.js +18 -345
- package/dist/base/build/src/index.d.ts +4 -2
- package/dist/base/build/src/index.js +2 -1
- package/dist/base/docs/migrations.md +5 -0
- package/dist/base/docs/public-workflow-cli.md +41 -5
- package/dist/base/docs/spec/builder-flow-runtime.md +117 -0
- package/dist/base/evals/integration/test_builder_step_producers.sh +60 -21
- package/dist/base/evals/integration/test_bundle_install.sh +15 -15
- package/dist/base/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
- package/dist/base/install.sh +1 -1
- package/dist/base/kits/builder/kit.json +88 -14
- package/dist/claude-code/build/package.json +1 -1
- package/dist/claude-code/build/src/builder-flow-run-adapter.d.ts +1 -0
- package/dist/claude-code/build/src/builder-flow-run-adapter.js +2 -0
- package/dist/claude-code/build/src/builder-flow-runtime.d.ts +5 -0
- package/dist/claude-code/build/src/builder-flow-runtime.js +90 -68
- package/dist/claude-code/build/src/builder-gate-action-envelope.d.ts +152 -0
- package/dist/claude-code/build/src/builder-gate-action-envelope.js +368 -0
- package/dist/claude-code/build/src/cli/public-contracts.d.ts +139 -0
- package/dist/claude-code/build/src/cli/public-contracts.js +37 -0
- package/dist/claude-code/build/src/cli/workflow-sidecar.js +9 -13
- package/dist/claude-code/build/src/cli/workflow.d.ts +1 -0
- package/dist/claude-code/build/src/cli/workflow.js +49 -12
- package/dist/claude-code/build/src/continuation-driver.d.ts +40 -3
- package/dist/claude-code/build/src/continuation-driver.js +361 -412
- package/dist/claude-code/build/src/continuation-persistence.d.ts +4 -0
- package/dist/claude-code/build/src/continuation-persistence.js +296 -0
- package/dist/claude-code/build/src/continuation-validation.d.ts +9 -0
- package/dist/claude-code/build/src/continuation-validation.js +169 -0
- package/dist/claude-code/build/src/flow-kit/action-metadata.d.ts +28 -0
- package/dist/claude-code/build/src/flow-kit/action-metadata.js +162 -0
- package/dist/claude-code/build/src/flow-kit/action-repository-validation.d.ts +16 -0
- package/dist/claude-code/build/src/flow-kit/action-repository-validation.js +237 -0
- package/dist/claude-code/build/src/flow-kit/validate.d.ts +2 -14
- package/dist/claude-code/build/src/flow-kit/validate.js +18 -345
- package/dist/claude-code/build/src/index.d.ts +4 -2
- package/dist/claude-code/build/src/index.js +2 -1
- package/dist/claude-code/docs/migrations.md +5 -0
- package/dist/claude-code/docs/public-workflow-cli.md +41 -5
- package/dist/claude-code/docs/spec/builder-flow-runtime.md +117 -0
- package/dist/claude-code/evals/integration/test_builder_step_producers.sh +60 -21
- package/dist/claude-code/evals/integration/test_bundle_install.sh +15 -15
- package/dist/claude-code/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
- package/dist/claude-code/install.sh +1 -1
- package/dist/claude-code/kits/builder/kit.json +88 -14
- package/dist/codex/build/package.json +1 -1
- package/dist/codex/build/src/builder-flow-run-adapter.d.ts +1 -0
- package/dist/codex/build/src/builder-flow-run-adapter.js +2 -0
- package/dist/codex/build/src/builder-flow-runtime.d.ts +5 -0
- package/dist/codex/build/src/builder-flow-runtime.js +90 -68
- package/dist/codex/build/src/builder-gate-action-envelope.d.ts +152 -0
- package/dist/codex/build/src/builder-gate-action-envelope.js +368 -0
- package/dist/codex/build/src/cli/public-contracts.d.ts +139 -0
- package/dist/codex/build/src/cli/public-contracts.js +37 -0
- package/dist/codex/build/src/cli/workflow-sidecar.js +9 -13
- package/dist/codex/build/src/cli/workflow.d.ts +1 -0
- package/dist/codex/build/src/cli/workflow.js +49 -12
- package/dist/codex/build/src/continuation-driver.d.ts +40 -3
- package/dist/codex/build/src/continuation-driver.js +361 -412
- package/dist/codex/build/src/continuation-persistence.d.ts +4 -0
- package/dist/codex/build/src/continuation-persistence.js +296 -0
- package/dist/codex/build/src/continuation-validation.d.ts +9 -0
- package/dist/codex/build/src/continuation-validation.js +169 -0
- package/dist/codex/build/src/flow-kit/action-metadata.d.ts +28 -0
- package/dist/codex/build/src/flow-kit/action-metadata.js +162 -0
- package/dist/codex/build/src/flow-kit/action-repository-validation.d.ts +16 -0
- package/dist/codex/build/src/flow-kit/action-repository-validation.js +237 -0
- package/dist/codex/build/src/flow-kit/validate.d.ts +2 -14
- package/dist/codex/build/src/flow-kit/validate.js +18 -345
- package/dist/codex/build/src/index.d.ts +4 -2
- package/dist/codex/build/src/index.js +2 -1
- package/dist/codex/docs/migrations.md +5 -0
- package/dist/codex/docs/public-workflow-cli.md +41 -5
- package/dist/codex/docs/spec/builder-flow-runtime.md +117 -0
- package/dist/codex/evals/integration/test_builder_step_producers.sh +60 -21
- package/dist/codex/evals/integration/test_bundle_install.sh +15 -15
- package/dist/codex/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
- package/dist/codex/install.sh +1 -1
- package/dist/codex/kits/builder/kit.json +88 -14
- package/dist/kiro/build/package.json +1 -1
- package/dist/kiro/build/src/builder-flow-run-adapter.d.ts +1 -0
- package/dist/kiro/build/src/builder-flow-run-adapter.js +2 -0
- package/dist/kiro/build/src/builder-flow-runtime.d.ts +5 -0
- package/dist/kiro/build/src/builder-flow-runtime.js +90 -68
- package/dist/kiro/build/src/builder-gate-action-envelope.d.ts +152 -0
- package/dist/kiro/build/src/builder-gate-action-envelope.js +368 -0
- package/dist/kiro/build/src/cli/public-contracts.d.ts +139 -0
- package/dist/kiro/build/src/cli/public-contracts.js +37 -0
- package/dist/kiro/build/src/cli/workflow-sidecar.js +9 -13
- package/dist/kiro/build/src/cli/workflow.d.ts +1 -0
- package/dist/kiro/build/src/cli/workflow.js +49 -12
- package/dist/kiro/build/src/continuation-driver.d.ts +40 -3
- package/dist/kiro/build/src/continuation-driver.js +361 -412
- package/dist/kiro/build/src/continuation-persistence.d.ts +4 -0
- package/dist/kiro/build/src/continuation-persistence.js +296 -0
- package/dist/kiro/build/src/continuation-validation.d.ts +9 -0
- package/dist/kiro/build/src/continuation-validation.js +169 -0
- package/dist/kiro/build/src/flow-kit/action-metadata.d.ts +28 -0
- package/dist/kiro/build/src/flow-kit/action-metadata.js +162 -0
- package/dist/kiro/build/src/flow-kit/action-repository-validation.d.ts +16 -0
- package/dist/kiro/build/src/flow-kit/action-repository-validation.js +237 -0
- package/dist/kiro/build/src/flow-kit/validate.d.ts +2 -14
- package/dist/kiro/build/src/flow-kit/validate.js +18 -345
- package/dist/kiro/build/src/index.d.ts +4 -2
- package/dist/kiro/build/src/index.js +2 -1
- package/dist/kiro/docs/migrations.md +5 -0
- package/dist/kiro/docs/public-workflow-cli.md +41 -5
- package/dist/kiro/docs/spec/builder-flow-runtime.md +117 -0
- package/dist/kiro/evals/integration/test_builder_step_producers.sh +60 -21
- package/dist/kiro/evals/integration/test_bundle_install.sh +15 -15
- package/dist/kiro/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
- package/dist/kiro/install.sh +1 -1
- package/dist/kiro/kits/builder/kit.json +88 -14
- package/dist/opencode/build/package.json +1 -1
- package/dist/opencode/build/src/builder-flow-run-adapter.d.ts +1 -0
- package/dist/opencode/build/src/builder-flow-run-adapter.js +2 -0
- package/dist/opencode/build/src/builder-flow-runtime.d.ts +5 -0
- package/dist/opencode/build/src/builder-flow-runtime.js +90 -68
- package/dist/opencode/build/src/builder-gate-action-envelope.d.ts +152 -0
- package/dist/opencode/build/src/builder-gate-action-envelope.js +368 -0
- package/dist/opencode/build/src/cli/public-contracts.d.ts +139 -0
- package/dist/opencode/build/src/cli/public-contracts.js +37 -0
- package/dist/opencode/build/src/cli/workflow-sidecar.js +9 -13
- package/dist/opencode/build/src/cli/workflow.d.ts +1 -0
- package/dist/opencode/build/src/cli/workflow.js +49 -12
- package/dist/opencode/build/src/continuation-driver.d.ts +40 -3
- package/dist/opencode/build/src/continuation-driver.js +361 -412
- package/dist/opencode/build/src/continuation-persistence.d.ts +4 -0
- package/dist/opencode/build/src/continuation-persistence.js +296 -0
- package/dist/opencode/build/src/continuation-validation.d.ts +9 -0
- package/dist/opencode/build/src/continuation-validation.js +169 -0
- package/dist/opencode/build/src/flow-kit/action-metadata.d.ts +28 -0
- package/dist/opencode/build/src/flow-kit/action-metadata.js +162 -0
- package/dist/opencode/build/src/flow-kit/action-repository-validation.d.ts +16 -0
- package/dist/opencode/build/src/flow-kit/action-repository-validation.js +237 -0
- package/dist/opencode/build/src/flow-kit/validate.d.ts +2 -14
- package/dist/opencode/build/src/flow-kit/validate.js +18 -345
- package/dist/opencode/build/src/index.d.ts +4 -2
- package/dist/opencode/build/src/index.js +2 -1
- package/dist/opencode/docs/migrations.md +5 -0
- package/dist/opencode/docs/public-workflow-cli.md +41 -5
- package/dist/opencode/docs/spec/builder-flow-runtime.md +117 -0
- package/dist/opencode/evals/integration/test_builder_step_producers.sh +60 -21
- package/dist/opencode/evals/integration/test_bundle_install.sh +15 -15
- package/dist/opencode/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
- package/dist/opencode/install.sh +1 -1
- package/dist/opencode/kits/builder/kit.json +88 -14
- package/dist/pi/build/package.json +1 -1
- package/dist/pi/build/src/builder-flow-run-adapter.d.ts +1 -0
- package/dist/pi/build/src/builder-flow-run-adapter.js +2 -0
- package/dist/pi/build/src/builder-flow-runtime.d.ts +5 -0
- package/dist/pi/build/src/builder-flow-runtime.js +90 -68
- package/dist/pi/build/src/builder-gate-action-envelope.d.ts +152 -0
- package/dist/pi/build/src/builder-gate-action-envelope.js +368 -0
- package/dist/pi/build/src/cli/public-contracts.d.ts +139 -0
- package/dist/pi/build/src/cli/public-contracts.js +37 -0
- package/dist/pi/build/src/cli/workflow-sidecar.js +9 -13
- package/dist/pi/build/src/cli/workflow.d.ts +1 -0
- package/dist/pi/build/src/cli/workflow.js +49 -12
- package/dist/pi/build/src/continuation-driver.d.ts +40 -3
- package/dist/pi/build/src/continuation-driver.js +361 -412
- package/dist/pi/build/src/continuation-persistence.d.ts +4 -0
- package/dist/pi/build/src/continuation-persistence.js +296 -0
- package/dist/pi/build/src/continuation-validation.d.ts +9 -0
- package/dist/pi/build/src/continuation-validation.js +169 -0
- package/dist/pi/build/src/flow-kit/action-metadata.d.ts +28 -0
- package/dist/pi/build/src/flow-kit/action-metadata.js +162 -0
- package/dist/pi/build/src/flow-kit/action-repository-validation.d.ts +16 -0
- package/dist/pi/build/src/flow-kit/action-repository-validation.js +237 -0
- package/dist/pi/build/src/flow-kit/validate.d.ts +2 -14
- package/dist/pi/build/src/flow-kit/validate.js +18 -345
- package/dist/pi/build/src/index.d.ts +4 -2
- package/dist/pi/build/src/index.js +2 -1
- package/dist/pi/docs/migrations.md +5 -0
- package/dist/pi/docs/public-workflow-cli.md +41 -5
- package/dist/pi/docs/spec/builder-flow-runtime.md +117 -0
- package/dist/pi/evals/integration/test_builder_step_producers.sh +60 -21
- package/dist/pi/evals/integration/test_bundle_install.sh +15 -15
- package/dist/pi/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
- package/dist/pi/install.sh +1 -1
- package/dist/pi/kits/builder/kit.json +88 -14
- package/docs/migrations.md +5 -0
- package/docs/public-workflow-cli.md +41 -5
- package/docs/spec/builder-flow-runtime.md +117 -0
- package/evals/integration/test_builder_step_producers.sh +60 -21
- package/evals/integration/test_bundle_install.sh +15 -15
- package/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
- package/kits/builder/kit.json +88 -14
- package/package.json +1 -1
- package/src/builder-flow-run-adapter.ts +3 -0
- package/src/builder-flow-runtime.ts +73 -46
- package/src/builder-gate-action-envelope.ts +531 -0
- package/src/cli/builder-flow-runtime.test.mjs +289 -58
- package/src/cli/continuation-driver.test.mjs +542 -24
- package/src/cli/kit-metadata-security.test.mjs +161 -8
- package/src/cli/public-contracts.ts +41 -0
- package/src/cli/workflow-sidecar.ts +9 -13
- package/src/cli/workflow.ts +48 -12
- package/src/continuation-driver.ts +466 -378
- package/src/continuation-persistence.ts +228 -0
- package/src/continuation-validation.ts +137 -0
- package/src/flow-kit/action-metadata.ts +155 -0
- package/src/flow-kit/action-repository-validation.ts +192 -0
- package/src/flow-kit/validate.ts +19 -326
- package/src/index.ts +17 -0
|
@@ -5,8 +5,9 @@ import os from "node:os";
|
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { createHash, generateKeyPairSync, sign, verify } from "node:crypto";
|
|
7
7
|
import { spawnSync } from "node:child_process";
|
|
8
|
+
import { createRequire } from "node:module";
|
|
8
9
|
|
|
9
|
-
import { FLOW_RUN_EVIDENCE_MANIFEST_PATH, runDir } from "@kontourai/flow";
|
|
10
|
+
import { FLOW_RUN_EVIDENCE_MANIFEST_PATH, acceptException, defaultFlowConfig, flowConfigPath, runDir } from "@kontourai/flow";
|
|
10
11
|
import {
|
|
11
12
|
archiveBuilderFlowSession,
|
|
12
13
|
cancelBuilderFlowSession,
|
|
@@ -19,11 +20,13 @@ import {
|
|
|
19
20
|
syncBuilderFlowSession,
|
|
20
21
|
} from "../../build/src/builder-flow-runtime.js";
|
|
21
22
|
import { builderLifecycleAuthorizationPayload, loadBuilderLifecycleAuthorization, recordAuthorizationConsumed } from "../../build/src/builder-lifecycle-authority.js";
|
|
22
|
-
import { driveBuilderFlowSession } from "../../build/src/continuation-driver.js";
|
|
23
|
-
import {
|
|
23
|
+
import { driveBuilderFlowSession, withContinuationDriverLock } from "../../build/src/continuation-driver.js";
|
|
24
|
+
import { deriveBuilderGateActionEnvelope } from "../../build/src/builder-gate-action-envelope.js";
|
|
25
|
+
import { WORKFLOW_CRITIQUE_STATUSES } from "../../build/src/cli/public-contracts.js";
|
|
26
|
+
import { cancelBuilderBuildRun, startBuilderFlowRun } from "../../build/src/builder-flow-run-adapter.js";
|
|
24
27
|
import { performLocalClaim, performLocalRelease, readLocalAssignmentStatus, resolveCurrentAssignmentActor } from "../../build/src/cli/assignment-provider.js";
|
|
25
28
|
import { main as builderRunMain } from "../../build/src/cli/builder-run.js";
|
|
26
|
-
import { main as workflowMain } from "../../build/src/cli/workflow.js";
|
|
29
|
+
import { assertAcceptedTurnEvidenceCapacity, main as workflowMain } from "../../build/src/cli/workflow.js";
|
|
27
30
|
import { buildTrustBundle, inferExecutedTestCount, main as workflowSidecarMain } from "../../build/src/cli/workflow-sidecar.js";
|
|
28
31
|
|
|
29
32
|
const SUBJECT = "local:work-item/runtime-projection";
|
|
@@ -33,6 +36,8 @@ const ACTOR = { runtime: "codex", session_id: "runtime-projection", host: "test-
|
|
|
33
36
|
const ACTOR_KEY = "codex:runtime-projection:test-host";
|
|
34
37
|
const AUTHORITY_KEY_ID = "runtime-test";
|
|
35
38
|
const AUTHORITY_KEYS = generateKeyPairSync("ed25519");
|
|
39
|
+
const require = createRequire(import.meta.url);
|
|
40
|
+
const activeTurnAuthority = require("../../scripts/hooks/lib/continuation-turn-authority.js");
|
|
36
41
|
const AMBIENT_IDENTITY_ENV_KEYS = [
|
|
37
42
|
"FLOW_AGENTS_ACTOR",
|
|
38
43
|
"CODEX_THREAD_ID",
|
|
@@ -243,6 +248,8 @@ function bundleClaim({ expectation, claimType, subjectType, status = "pass", rou
|
|
|
243
248
|
value: status,
|
|
244
249
|
metadata: {
|
|
245
250
|
workflow_subject_ref: subject,
|
|
251
|
+
origin: "check",
|
|
252
|
+
check_kind: "external",
|
|
246
253
|
...(expectation === "tests-evidence" ? {
|
|
247
254
|
recorded_by: "implementation-actor",
|
|
248
255
|
artifact_refs: [{ kind: "command", excerpt: "node --test src/cli/builder-flow-runtime.test.mjs", summary: "Runtime fixture assertion." }],
|
|
@@ -363,6 +370,26 @@ test("small-model client can start and advance from projected actions without ch
|
|
|
363
370
|
assert.match(started.projection.next_action.command, /--prefix "\$root"/);
|
|
364
371
|
assert.ok(started.projection.next_action.command.includes(`'@kontourai/flow-agents@${PACKAGE_VERSION}'`));
|
|
365
372
|
assert.ok(started.projection.next_action.command.includes(`'workflow' 'status' '--session-dir' '.kontourai/flow-agents/${session.slug}' '--json'`));
|
|
373
|
+
const envelope = started.gateActionEnvelope;
|
|
374
|
+
assert.equal(Object.hasOwn(started.projection.next_action, "gate_action_envelope"), false, "durable state has no duplicate envelope");
|
|
375
|
+
assert.equal(envelope.schema_version, "2.0");
|
|
376
|
+
assert.equal(envelope.gate.requirements[0].gate_id, "pull-work-gate");
|
|
377
|
+
assert.equal(envelope.action.implementation_allowed, false, "implementation is forbidden before builder.build/execute");
|
|
378
|
+
assert.deepEqual(envelope.action.declared_evidence, ["selected-work"]);
|
|
379
|
+
assert.deepEqual(envelope.action.declared_artifacts, [`<slug>--pull-work.md`, "trust.bundle#selected-work"]);
|
|
380
|
+
assert.equal(envelope.stop_condition.kind, "one_turn");
|
|
381
|
+
assert.equal(envelope.stop_condition.scope.current_gate_only, true);
|
|
382
|
+
assert.deepEqual(envelope.stop_condition.required.unresolved_evidence_ids, ["selected-work"]);
|
|
383
|
+
assert.deepEqual(envelope.stop_condition.sequence, ["activate_required_skills", "produce_declared_artifacts", "record_bound_evidence", "synchronize_canonical_flow", "return_adapter_result"]);
|
|
384
|
+
assert.equal(envelope.stop_condition.adapter_evidence_is_gate_evidence, false);
|
|
385
|
+
assert.equal(envelope.action.skills[0].id, "pull-work");
|
|
386
|
+
assert.equal(envelope.action.skills[0].package.name, "@kontourai/flow-agents");
|
|
387
|
+
assert.match(envelope.action.skills[0].path, /kits\/builder\/skills\/pull-work\/SKILL\.md$/);
|
|
388
|
+
assert.match(envelope.action.skills[0].sha256, /^[a-f0-9]{64}$/);
|
|
389
|
+
assert.equal(envelope.public_interfaces.mutations[0].expectation_id, "selected-work");
|
|
390
|
+
assert.deepEqual(envelope.public_interfaces.mutations[0].package, { name: "@kontourai/flow-agents", version: PACKAGE_VERSION });
|
|
391
|
+
assert.deepEqual(envelope.public_interfaces.mutations[0].argv.slice(0, 2), ["workflow", "evidence"]);
|
|
392
|
+
assert.equal(envelope.public_interfaces.mutations[0].argv.some((value) => value.includes("<")), false, "argv contains no substitution placeholders");
|
|
366
393
|
assert.ok(fs.existsSync(runDir(session.slug, session.projectRoot)));
|
|
367
394
|
assert.ok(!fs.existsSync(path.join(session.projectRoot, ".flow", "runs")), "retired runtime path must not be created");
|
|
368
395
|
|
|
@@ -375,6 +402,8 @@ test("small-model client can start and advance from projected actions without ch
|
|
|
375
402
|
assert.equal(advanced.attached, true);
|
|
376
403
|
assert.equal(advanced.run.state.current_step, "design-probe");
|
|
377
404
|
assert.deepEqual(advanced.projection.next_action.skills, ["pickup-probe"]);
|
|
405
|
+
assert.equal(advanced.gateActionEnvelope.action.implementation_allowed, false);
|
|
406
|
+
assert.equal(advanced.gateActionEnvelope.progress.canonical_evidence.some((entry) => entry.startsWith("pull-work-gate:")), true, "advancing evidence remains attributable after the step namespace changes");
|
|
378
407
|
assert.equal(readJson(path.join(session.artifactRoot, "current.json")).active_step_id, "design-probe");
|
|
379
408
|
|
|
380
409
|
const duplicate = await syncBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
@@ -382,6 +411,49 @@ test("small-model client can start and advance from projected actions without ch
|
|
|
382
411
|
assert.equal(duplicate.run.manifest.evidence.length, advanced.run.manifest.evidence.length);
|
|
383
412
|
});
|
|
384
413
|
|
|
414
|
+
test("gate-action implementation policy permits code only at builder.build/execute", async () => {
|
|
415
|
+
const session = makeSession("gate-action-implementation-policy");
|
|
416
|
+
await startBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
417
|
+
await writeAndSync(session, [bundleClaim({ expectation: "selected-work", claimType: "builder.pull-work.selected", subjectType: "work-item" })]);
|
|
418
|
+
await writeAndSync(session, [
|
|
419
|
+
bundleClaim({ expectation: "pickup-probe-readiness", claimType: "builder.design-probe.pickup-readiness", subjectType: "work-item" }),
|
|
420
|
+
bundleClaim({ expectation: "probe-decisions-or-accepted-gaps", claimType: "builder.design-probe.decisions", subjectType: "decision" }),
|
|
421
|
+
]);
|
|
422
|
+
const executing = await writeAndSync(session, [bundleClaim({ expectation: "implementation-plan", claimType: "builder.plan.implementation", subjectType: "artifact" })]);
|
|
423
|
+
assert.equal(executing.run.state.current_step, "execute");
|
|
424
|
+
assert.equal(executing.gateActionEnvelope.action.implementation_allowed, true);
|
|
425
|
+
assert.equal(executing.gateActionEnvelope.action.declared_artifacts.includes("state.json"), false, "control state is not a declared model artifact");
|
|
426
|
+
assert.equal(executing.gateActionEnvelope.stop_condition.required.artifact_refs.includes("state.json"), false, "control state is not a required model artifact");
|
|
427
|
+
assert.equal(executing.gateActionEnvelope.progress.observed_artifacts.some((entry) => entry.startsWith("state.json:")), false, "control state never counts as progress");
|
|
428
|
+
|
|
429
|
+
const requests = [];
|
|
430
|
+
await driveBuilderFlowSession({
|
|
431
|
+
sessionDir: session.sessionDir,
|
|
432
|
+
maxTurns: 2,
|
|
433
|
+
execute: async (request) => { requests.push(request); return { status: "completed" }; },
|
|
434
|
+
});
|
|
435
|
+
assert.equal(requests.length, 2);
|
|
436
|
+
assert.equal(requests[1].gate_action_envelope.progress.prior_turn.stagnation, "possible");
|
|
437
|
+
const mission = readJson(path.join(session.sessionDir, "continuation-driver", "state.json"));
|
|
438
|
+
assert.equal(mission.prior_progress.stagnation, "stagnant", "two no-op execute turns are true stagnation");
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
test("gate-action artifact identity reads reject symlinks and oversized files", async (t) => {
|
|
442
|
+
await t.test("symlink", async () => {
|
|
443
|
+
const session = makeSession("gate-action-artifact-symlink");
|
|
444
|
+
const outside = path.join(session.projectRoot, "outside-release.json");
|
|
445
|
+
fs.writeFileSync(outside, "{}\n");
|
|
446
|
+
fs.symlinkSync(outside, path.join(session.sessionDir, "release.json"));
|
|
447
|
+
await assert.rejects(startBuilderFlowSession({ sessionDir: session.sessionDir }), /ELOOP|regular file|changed identity/);
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
await t.test("oversized", async () => {
|
|
451
|
+
const session = makeSession("gate-action-artifact-oversized");
|
|
452
|
+
fs.writeFileSync(path.join(session.sessionDir, "release.json"), Buffer.alloc(1_048_577));
|
|
453
|
+
await assert.rejects(startBuilderFlowSession({ sessionDir: session.sessionDir }), /bounded regular file/);
|
|
454
|
+
});
|
|
455
|
+
});
|
|
456
|
+
|
|
385
457
|
test("Builder projection preserves Flow continuation semantics for exceptional statuses", async () => {
|
|
386
458
|
const session = makeSession("continuation-status-projection");
|
|
387
459
|
await startBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
@@ -399,7 +471,51 @@ test("Builder projection preserves Flow continuation semantics for exceptional s
|
|
|
399
471
|
}
|
|
400
472
|
});
|
|
401
473
|
|
|
402
|
-
test("
|
|
474
|
+
test("accepted Flow exceptions explicitly waive the current envelope requirements", async () => {
|
|
475
|
+
const session = makeSession("accepted-exception-envelope");
|
|
476
|
+
await startBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
477
|
+
const exception = await acceptException(session.slug, {
|
|
478
|
+
cwd: session.projectRoot,
|
|
479
|
+
gate: "pull-work-gate",
|
|
480
|
+
reason: "authorized fixture waiver",
|
|
481
|
+
authority: "test-reviewer",
|
|
482
|
+
});
|
|
483
|
+
const recovered = await recoverBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
484
|
+
assert.deepEqual(recovered.gateActionEnvelope.gate.accepted_exceptions, [{ gate_id: "pull-work-gate", exception_id: exception.id }]);
|
|
485
|
+
assert.equal(recovered.gateActionEnvelope.gate.requirements[0].gate_id, "pull-work-gate");
|
|
486
|
+
assert.equal(recovered.gateActionEnvelope.gate.requirements[0].status, "accepted_exception");
|
|
487
|
+
assert.deepEqual(recovered.gateActionEnvelope.stop_condition.required.unresolved_evidence_ids, []);
|
|
488
|
+
assert.deepEqual(recovered.gateActionEnvelope.stop_condition.required.artifact_refs, []);
|
|
489
|
+
assert.deepEqual(recovered.gateActionEnvelope.stop_condition.required.skill_ids, []);
|
|
490
|
+
const synchronized = await syncBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
491
|
+
assert.equal(synchronized.attached, false);
|
|
492
|
+
assert.equal(synchronized.run.state.current_step, "design-probe");
|
|
493
|
+
assert.deepEqual(synchronized.gateActionEnvelope.action.skills.map((skill) => skill.id), ["pickup-probe"]);
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
test("all-optional effective Flow gate overrides advance during canonical sync without bundle evidence", async () => {
|
|
497
|
+
const session = makeSession("gate-override-envelope");
|
|
498
|
+
const config = defaultFlowConfig();
|
|
499
|
+
config.gate_overrides["pull-work-gate"] = { expectations: { "selected-work": { required: false } } };
|
|
500
|
+
fs.mkdirSync(path.dirname(flowConfigPath(session.projectRoot)), { recursive: true });
|
|
501
|
+
writeJson(flowConfigPath(session.projectRoot), config);
|
|
502
|
+
const unevaluated = await startBuilderFlowRun({ cwd: session.projectRoot, runId: session.slug, subject: SUBJECT, flowId: "builder.build" });
|
|
503
|
+
const directEnvelope = deriveBuilderGateActionEnvelope({
|
|
504
|
+
sessionDir: session.sessionDir,
|
|
505
|
+
projectRoot: session.projectRoot,
|
|
506
|
+
run: unevaluated,
|
|
507
|
+
definition: readJson(path.join(unevaluated.dir, "definition.json")),
|
|
508
|
+
});
|
|
509
|
+
assert.deepEqual(directEnvelope.stop_condition.required.skill_ids, []);
|
|
510
|
+
fs.rmSync(unevaluated.dir, { recursive: true, force: true });
|
|
511
|
+
const started = await startBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
512
|
+
assert.equal(started.attached, false);
|
|
513
|
+
assert.equal(started.run.state.current_step, "design-probe");
|
|
514
|
+
assert.deepEqual(started.gateActionEnvelope.action.skills.map((skill) => skill.id), ["pickup-probe"]);
|
|
515
|
+
assert.equal(started.gateActionEnvelope.flow.current_step, "design-probe");
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
test("weak structured consumer advances real Builder gates through envelope public interfaces", async () => {
|
|
403
519
|
const session = makeSession("continuation-driver-two-steps");
|
|
404
520
|
await startBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
405
521
|
const visited = [];
|
|
@@ -409,13 +525,14 @@ test("continuation driver advances two real FlowDefinition steps unattended", as
|
|
|
409
525
|
maxTurns: 2,
|
|
410
526
|
execute: async (request) => {
|
|
411
527
|
visited.push(request.current_step);
|
|
412
|
-
|
|
528
|
+
const expectationIds = request.gate_action_envelope.public_interfaces.mutations.map((mutation) => mutation.expectation_id);
|
|
529
|
+
if (expectationIds.includes("selected-work")) {
|
|
413
530
|
writeBundle(session.sessionDir, [bundleClaim({
|
|
414
531
|
expectation: "selected-work",
|
|
415
532
|
claimType: "builder.pull-work.selected",
|
|
416
533
|
subjectType: "work-item",
|
|
417
534
|
})]);
|
|
418
|
-
} else if (
|
|
535
|
+
} else if (expectationIds.includes("pickup-probe-readiness")) {
|
|
419
536
|
writeBundle(session.sessionDir, [
|
|
420
537
|
bundleClaim({
|
|
421
538
|
expectation: "pickup-probe-readiness",
|
|
@@ -429,7 +546,7 @@ test("continuation driver advances two real FlowDefinition steps unattended", as
|
|
|
429
546
|
}),
|
|
430
547
|
]);
|
|
431
548
|
} else {
|
|
432
|
-
assert.fail(`unexpected
|
|
549
|
+
assert.fail(`unexpected public mutation set ${expectationIds.join(",")}`);
|
|
433
550
|
}
|
|
434
551
|
return { status: "completed", summary: `completed ${request.current_step}` };
|
|
435
552
|
},
|
|
@@ -478,8 +595,10 @@ test("public workflow evidence accepts only live signed turn authority after ord
|
|
|
478
595
|
const ordinaryChild = ${JSON.stringify(path.resolve(import.meta.dirname, "../../scripts/hooks/lib/actor-identity.js"))};
|
|
479
596
|
const childIdentity = (await import("node:module")).createRequire(import.meta.url)(ordinaryChild).resolveActorIdentity(evidenceEnv);
|
|
480
597
|
const record = (expectation) => {
|
|
598
|
+
const binding = request.gate_action_envelope.public_interfaces.mutations.find((entry) => entry.expectation_id === expectation && entry.interface === "workflow.evidence");
|
|
599
|
+
if (!binding) throw new Error("missing workflow.evidence binding for " + expectation);
|
|
481
600
|
const evidence = { kind: "artifact", file: ${JSON.stringify(`.kontourai/flow-agents/${session.slug}/${session.slug}--pull-work.md`)}, summary: "adapter child records " + expectation };
|
|
482
|
-
return spawnSync(process.execPath, [${JSON.stringify(path.resolve(import.meta.dirname, "../../build/src/cli.js"))},
|
|
601
|
+
return spawnSync(process.execPath, [${JSON.stringify(path.resolve(import.meta.dirname, "../../build/src/cli.js"))}, ...binding.argv, "--status", "pass", "--summary", "adapter child records " + expectation, "--evidence-ref-json", JSON.stringify(evidence)], { cwd: ${JSON.stringify(session.projectRoot)}, encoding: "utf8", env: evidenceEnv });
|
|
483
602
|
};
|
|
484
603
|
const evidenceRuns = request.current_step === "pull-work"
|
|
485
604
|
? [record("selected-work")]
|
|
@@ -556,6 +675,14 @@ test("public workflow evidence accepts only live signed turn authority after ord
|
|
|
556
675
|
assert.notEqual(forged.status, 0, "fake nonce and digest without a signed active turn fail ownership");
|
|
557
676
|
});
|
|
558
677
|
|
|
678
|
+
test("signed turn evidence capacity is rejected by preflight before another bounded result", () => {
|
|
679
|
+
assert.doesNotThrow(() => assertAcceptedTurnEvidenceCapacity([], { schema_version: "1.0", iteration: 1 }));
|
|
680
|
+
assert.throws(
|
|
681
|
+
() => assertAcceptedTurnEvidenceCapacity([{ request: { padding: "x".repeat(980_000) }, result: {} }], { schema_version: "1.0", iteration: 2 }),
|
|
682
|
+
/lacks capacity for another bounded result/,
|
|
683
|
+
);
|
|
684
|
+
});
|
|
685
|
+
|
|
559
686
|
test("public workflow drive signs adapter evidence with a consumed one-time key", async () => {
|
|
560
687
|
const session = makeSession("continuation-driver-signed-evidence");
|
|
561
688
|
claimAmbientSessionAssignment(session);
|
|
@@ -636,6 +763,8 @@ test("public workflow drive signs adapter evidence with a consumed one-time key"
|
|
|
636
763
|
assert.deepEqual(payload.adapter_turns.map((turn) => turn.request), observedRequests);
|
|
637
764
|
assert.equal(payload.adapter_turns[0].request.schema_version, "1.0");
|
|
638
765
|
assert.equal(payload.adapter_turns[0].request.next_action.status, "continue");
|
|
766
|
+
assert.equal(payload.adapter_turns[0].request.gate_action_envelope.schema_version, "2.0");
|
|
767
|
+
assert.deepEqual(payload.adapter_turns.map((turn) => turn.request), observedRequests, "the signed payload binds the unchanged envelope bytes observed by the adapter");
|
|
639
768
|
assert.deepEqual(payload.adapter_turns[0].result.evidence.usage, { input_tokens: 10, output_tokens: 2 });
|
|
640
769
|
const tampered = Buffer.from(JSON.stringify({ ...payload, max_turns: 2 }));
|
|
641
770
|
assert.equal(verify(null, tampered, keys.publicKey, Buffer.from(attestation.signature_b64, "base64")), false);
|
|
@@ -1148,6 +1277,43 @@ test("partial passing review snapshot waits for the complete verify expectation
|
|
|
1148
1277
|
assert.equal(partial.run.state.current_step, "verify");
|
|
1149
1278
|
assert.equal(partial.run.state.transitions.filter((transition) => transition.type === "route_back").length, 0);
|
|
1150
1279
|
|
|
1280
|
+
const definition = readJson(path.join(partial.run.dir, "definition.json"));
|
|
1281
|
+
const validPartialBundle = readJson(path.join(session.sessionDir, "trust.bundle"));
|
|
1282
|
+
const validPartialEvidence = {
|
|
1283
|
+
id: "partial-verify-evidence",
|
|
1284
|
+
gate_id: "verify-gate",
|
|
1285
|
+
kind: "trust.bundle",
|
|
1286
|
+
requested_kind: "trust.bundle",
|
|
1287
|
+
sha256: "a".repeat(64),
|
|
1288
|
+
status: "passed",
|
|
1289
|
+
attached_at: new Date().toISOString(),
|
|
1290
|
+
expectation_ids: ["clean-critique"],
|
|
1291
|
+
bundle: validPartialBundle,
|
|
1292
|
+
};
|
|
1293
|
+
const partialEnvelope = deriveBuilderGateActionEnvelope({
|
|
1294
|
+
sessionDir: session.sessionDir,
|
|
1295
|
+
projectRoot: session.projectRoot,
|
|
1296
|
+
run: {
|
|
1297
|
+
...partial.run,
|
|
1298
|
+
manifest: {
|
|
1299
|
+
...partial.run.manifest,
|
|
1300
|
+
evidence: [...partial.run.manifest.evidence, validPartialEvidence],
|
|
1301
|
+
},
|
|
1302
|
+
},
|
|
1303
|
+
definition,
|
|
1304
|
+
});
|
|
1305
|
+
assert.equal(partialEnvelope.gate.requirements.find((entry) => entry.id === "clean-critique").status, "satisfied");
|
|
1306
|
+
assert.deepEqual(partialEnvelope.gate.unresolved_requirement_ids.sort(), ["acceptance-criteria", "policy-compliance", "tests-evidence"]);
|
|
1307
|
+
assert.equal(partialEnvelope.gate.requirements.find((entry) => entry.id === "policy-compliance").required, false);
|
|
1308
|
+
assert.deepEqual(partialEnvelope.stop_condition.required.unresolved_evidence_ids.sort(), ["acceptance-criteria", "tests-evidence"]);
|
|
1309
|
+
assert.equal(partialEnvelope.stop_condition.required.artifact_refs.includes("trust.bundle#policy-compliance"), false);
|
|
1310
|
+
const critique = partialEnvelope.public_interfaces.mutations.find((entry) => entry.interface === "workflow.critique");
|
|
1311
|
+
assert.deepEqual(critique.parameters.find((entry) => entry.name === "verdict").allowed_values, [...WORKFLOW_CRITIQUE_STATUSES]);
|
|
1312
|
+
assert.deepEqual(critique.parameters.find((entry) => entry.name === "artifact_ref"), {
|
|
1313
|
+
name: "artifact_ref", flag: "--artifact-ref", required: false, repeatable: true,
|
|
1314
|
+
required_when: { parameter: "verdict", equals: "pass" },
|
|
1315
|
+
});
|
|
1316
|
+
|
|
1151
1317
|
const complete = await writeAndSync(session, [
|
|
1152
1318
|
bundleClaim({ expectation: "tests-evidence", claimType: "builder.verify.tests", subjectType: "flow-step" }),
|
|
1153
1319
|
...verifiedTestsPrerequisites(session),
|
|
@@ -1155,6 +1321,48 @@ test("partial passing review snapshot waits for the complete verify expectation
|
|
|
1155
1321
|
assert.equal(complete.run.state.current_step, "merge-ready");
|
|
1156
1322
|
});
|
|
1157
1323
|
|
|
1324
|
+
test("expectation_ids labels cannot satisfy a mismatched trust bundle claim", async () => {
|
|
1325
|
+
const session = makeSession("mislabeled-partial-gate");
|
|
1326
|
+
await startBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
1327
|
+
await writeAndSync(session, [bundleClaim({ expectation: "selected-work", claimType: "builder.pull-work.selected", subjectType: "work-item" })]);
|
|
1328
|
+
await writeAndSync(session, [
|
|
1329
|
+
bundleClaim({ expectation: "pickup-probe-readiness", claimType: "builder.design-probe.pickup-readiness", subjectType: "work-item" }),
|
|
1330
|
+
bundleClaim({ expectation: "probe-decisions-or-accepted-gaps", claimType: "builder.design-probe.decisions", subjectType: "decision" }),
|
|
1331
|
+
]);
|
|
1332
|
+
await writeAndSync(session, [bundleClaim({ expectation: "implementation-plan", claimType: "builder.plan.implementation", subjectType: "artifact" })]);
|
|
1333
|
+
await writeAndSync(session, [bundleClaim({ expectation: "implementation-scope", claimType: "builder.execute.scope", subjectType: "change" })]);
|
|
1334
|
+
const partial = await writeAndSync(session, verifiedTestsPrerequisites(session).slice(0, 1));
|
|
1335
|
+
|
|
1336
|
+
const mislabeledBundle = readJson(path.join(session.sessionDir, "trust.bundle"));
|
|
1337
|
+
mislabeledBundle.claims[0].claimType = "workflow.critique.wrong-claim";
|
|
1338
|
+
const definition = readJson(path.join(partial.run.dir, "definition.json"));
|
|
1339
|
+
const envelope = deriveBuilderGateActionEnvelope({
|
|
1340
|
+
sessionDir: session.sessionDir,
|
|
1341
|
+
projectRoot: session.projectRoot,
|
|
1342
|
+
run: {
|
|
1343
|
+
...partial.run,
|
|
1344
|
+
manifest: {
|
|
1345
|
+
...partial.run.manifest,
|
|
1346
|
+
evidence: [...partial.run.manifest.evidence, {
|
|
1347
|
+
id: "mislabeled-partial-verify-evidence",
|
|
1348
|
+
gate_id: "verify-gate",
|
|
1349
|
+
kind: "trust.bundle",
|
|
1350
|
+
requested_kind: "trust.bundle",
|
|
1351
|
+
sha256: "b".repeat(64),
|
|
1352
|
+
status: "passed",
|
|
1353
|
+
attached_at: new Date().toISOString(),
|
|
1354
|
+
expectation_ids: ["clean-critique"],
|
|
1355
|
+
bundle: mislabeledBundle,
|
|
1356
|
+
}],
|
|
1357
|
+
},
|
|
1358
|
+
},
|
|
1359
|
+
definition,
|
|
1360
|
+
});
|
|
1361
|
+
|
|
1362
|
+
assert.equal(envelope.gate.requirements.find((entry) => entry.id === "clean-critique").status, "unresolved");
|
|
1363
|
+
assert.equal(envelope.gate.unresolved_requirement_ids.includes("clean-critique"), true);
|
|
1364
|
+
});
|
|
1365
|
+
|
|
1158
1366
|
test("initial gate boundary rejects pre-run and far-future claims", async () => {
|
|
1159
1367
|
for (const [name, timestamp] of [
|
|
1160
1368
|
["pre-run", NOW],
|
|
@@ -1345,9 +1553,9 @@ test("workspace review fails closed when a Git worktree marker cannot be inspect
|
|
|
1345
1553
|
);
|
|
1346
1554
|
});
|
|
1347
1555
|
|
|
1348
|
-
test("
|
|
1556
|
+
test("publish-change reports an external capability gap and self-authored results cannot pass", async () => {
|
|
1349
1557
|
const session = makeSession("composed-completion");
|
|
1350
|
-
|
|
1558
|
+
const ambient = claimAmbientSessionAssignment(session);
|
|
1351
1559
|
await startBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
1352
1560
|
const steps = [
|
|
1353
1561
|
() => [bundleClaim({ expectation: "selected-work", claimType: "builder.pull-work.selected", subjectType: "work-item" })],
|
|
@@ -1367,55 +1575,78 @@ test("verified sidecar claims drive the composed publish and learning prefix to
|
|
|
1367
1575
|
assert.equal(readJson(path.join(session.artifactRoot, "current.json")).active_step_id, "pr-open");
|
|
1368
1576
|
assert.deepEqual(prOpen.next_action.skills, []);
|
|
1369
1577
|
assert.deepEqual(prOpen.next_action.operations, ["publish-change"]);
|
|
1578
|
+
assert.equal(prOpen.next_action.status, "blocked");
|
|
1579
|
+
assert.equal(prOpen.next_action.external_capability.completion, "external_verification_required");
|
|
1580
|
+
|
|
1581
|
+
const operationView = await syncBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
1582
|
+
const publish = operationView.gateActionEnvelope.public_interfaces.mutations.find((entry) => entry.interface === "operation");
|
|
1583
|
+
assert.equal(publish.operation, "publish-change");
|
|
1584
|
+
assert.equal(publish.protocol.capability, "pull_request.create");
|
|
1585
|
+
assert.deepEqual(publish.protocol.result.required, ["provider", "repository", "number", "url", "head_ref", "base_ref"]);
|
|
1586
|
+
assert.deepEqual(publish.protocol.result.properties.number, { type: "integer", minimum: 1 });
|
|
1587
|
+
assert.deepEqual(publish.protocol.result.url_protocols, ["https:"]);
|
|
1588
|
+
assert.equal(publish.protocol.result.persist_as, "publish-change.result.json");
|
|
1589
|
+
assert.deepEqual(publish.completion, {
|
|
1590
|
+
status: "external_verification_required",
|
|
1591
|
+
executable_by_flow_agents: false,
|
|
1592
|
+
gate_evidence_interface: null,
|
|
1593
|
+
});
|
|
1594
|
+
assert.equal(Object.hasOwn(publish, "record_completion"), false);
|
|
1595
|
+
const providerResult = { provider: "fixture", repository: "kontourai/flow-agents", number: 577, url: "https://example.test/kontourai/flow-agents/pull/577", head_ref: "issue-577", base_ref: "main" };
|
|
1596
|
+
writeJson(path.join(session.sessionDir, publish.protocol.result.persist_as), providerResult);
|
|
1597
|
+
const unchanged = await syncBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
1598
|
+
assert.equal(unchanged.attached, false);
|
|
1599
|
+
assert.equal(unchanged.run.state.current_step, "pr-open");
|
|
1600
|
+
assert.equal(unchanged.projection.next_action.status, "blocked");
|
|
1601
|
+
assert.equal(unchanged.run.manifest.evidence.some((entry) => entry.expectation_ids?.includes("pull-request-opened")), false);
|
|
1602
|
+
const beforeFlow = snapshotTree(runDir(session.slug, session.projectRoot));
|
|
1603
|
+
const beforeProjection = snapshotProjectionTargets(session);
|
|
1604
|
+
const genericEvidenceArgs = ["evidence", "--session-dir", session.sessionDir, "--expectation", "pull-request-opened", "--status", "pass", "--summary", "self-completion", "--evidence-ref-json", JSON.stringify({ kind: "artifact", file: `.kontourai/flow-agents/${session.slug}/publish-change.result.json`, summary: "locally authored provider-shaped result" })];
|
|
1605
|
+
await assert.rejects(
|
|
1606
|
+
() => workflowMain(genericEvidenceArgs),
|
|
1607
|
+
/operation-bound expectation.*authenticated external ChangeProvider/,
|
|
1608
|
+
);
|
|
1609
|
+
assert.deepEqual(snapshotTree(runDir(session.slug, session.projectRoot)), beforeFlow);
|
|
1610
|
+
assert.deepEqual(snapshotProjectionTargets(session), beforeProjection);
|
|
1370
1611
|
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
writeJson(path.join(session.sessionDir, "state.json"), staleState);
|
|
1406
|
-
const recovered = await recoverBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
1407
|
-
assert.equal(recovered.attached, false);
|
|
1408
|
-
assert.equal(recovered.projection.status, "delivered");
|
|
1409
|
-
assert.equal(recovered.projection.phase, "done");
|
|
1410
|
-
assert.deepEqual(recovered.projection.next_action, { status: "done", summary: "Canonical Flow run is complete." });
|
|
1411
|
-
assert.deepEqual(snapshotTree(flowDirectory), beforeFlow);
|
|
1412
|
-
|
|
1413
|
-
const archived = await archiveBuilderFlowSession({
|
|
1414
|
-
sessionDir: session.sessionDir,
|
|
1415
|
-
authorizationFile: liveLifecycleAuthorization(session, "archive", "completed-archive"),
|
|
1612
|
+
await withContinuationDriverLock(session.sessionDir, async (lock) => {
|
|
1613
|
+
const driverDir = path.join(session.sessionDir, "continuation-driver");
|
|
1614
|
+
writeJson(path.join(driverDir, "state.json"), {
|
|
1615
|
+
schema_version: "1.0", run_id: session.slug, definition_id: "builder.build", max_turns: 1,
|
|
1616
|
+
adapter_command_identity: "operation-rejection-test", status: "active", turns_started: 1,
|
|
1617
|
+
active_turn_step: "pr-open", active_turn_public_key_digest: null, pending_barrier: null,
|
|
1618
|
+
});
|
|
1619
|
+
const issued = activeTurnAuthority.issueActiveTurnAuthority({
|
|
1620
|
+
sessionDir: session.sessionDir,
|
|
1621
|
+
runId: session.slug,
|
|
1622
|
+
definitionId: "builder.build",
|
|
1623
|
+
currentStep: "pr-open",
|
|
1624
|
+
iteration: 1,
|
|
1625
|
+
maxTurns: 1,
|
|
1626
|
+
adapterCommandIdentity: "operation-rejection-test",
|
|
1627
|
+
assignmentActor: ambient.actorKey,
|
|
1628
|
+
assignmentActorStruct: ambient.actor,
|
|
1629
|
+
lock,
|
|
1630
|
+
timeoutMs: 10_000,
|
|
1631
|
+
});
|
|
1632
|
+
writeJson(path.join(driverDir, "state.json"), {
|
|
1633
|
+
...readJson(path.join(driverDir, "state.json")),
|
|
1634
|
+
active_turn_public_key_digest: issued.publicKeyDigest,
|
|
1635
|
+
});
|
|
1636
|
+
const signedEnv = {
|
|
1637
|
+
...process.env,
|
|
1638
|
+
FLOW_AGENTS_CONTINUATION_RUN_ID: issued.runId,
|
|
1639
|
+
FLOW_AGENTS_CONTINUATION_TURN_SECRET: issued.turnSecret,
|
|
1640
|
+
};
|
|
1641
|
+
for (const key of AMBIENT_IDENTITY_ENV_KEYS) delete signedEnv[key];
|
|
1642
|
+
const signed = spawnSync(process.execPath, [path.resolve(import.meta.dirname, "../../build/src/cli.js"), "workflow", ...genericEvidenceArgs], { cwd: session.projectRoot, encoding: "utf8", env: signedEnv });
|
|
1643
|
+
assert.notEqual(signed.status, 0);
|
|
1644
|
+
assert.match(signed.stderr, /operation-bound expectation.*authenticated external ChangeProvider/);
|
|
1645
|
+
assert.equal(issued.cleanup(), true);
|
|
1416
1646
|
});
|
|
1417
|
-
assert.
|
|
1418
|
-
assert.deepEqual(
|
|
1647
|
+
assert.deepEqual(snapshotTree(runDir(session.slug, session.projectRoot)), beforeFlow);
|
|
1648
|
+
assert.deepEqual(snapshotProjectionTargets(session), beforeProjection);
|
|
1649
|
+
await releaseBuilderFlowAssignment({ sessionDir: session.sessionDir, reason: `test cleanup for ${ambient.actorKey}` });
|
|
1419
1650
|
});
|
|
1420
1651
|
|
|
1421
1652
|
test("recovery loads the slug-bound run, restores every matching projection, and preserves every Flow byte", async () => {
|