@kontourai/flow-agents 3.11.0 → 3.12.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.
- package/CHANGELOG.md +7 -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 +151 -0
- package/build/src/builder-gate-action-envelope.js +367 -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 +139 -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 +151 -0
- package/dist/base/build/src/builder-gate-action-envelope.js +367 -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 +139 -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/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 +151 -0
- package/dist/claude-code/build/src/builder-gate-action-envelope.js +367 -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 +139 -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/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 +151 -0
- package/dist/codex/build/src/builder-gate-action-envelope.js +367 -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 +139 -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/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 +151 -0
- package/dist/kiro/build/src/builder-gate-action-envelope.js +367 -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 +139 -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/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 +151 -0
- package/dist/opencode/build/src/builder-gate-action-envelope.js +367 -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 +139 -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/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 +151 -0
- package/dist/pi/build/src/builder-gate-action-envelope.js +367 -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 +139 -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/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/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 +529 -0
- package/src/cli/builder-flow-runtime.test.mjs +287 -58
- package/src/cli/continuation-driver.test.mjs +527 -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 +107 -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,25 @@ 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, "1.0");
|
|
376
|
+
assert.equal(envelope.action.implementation_allowed, false, "implementation is forbidden before builder.build/execute");
|
|
377
|
+
assert.deepEqual(envelope.action.declared_evidence, ["selected-work"]);
|
|
378
|
+
assert.deepEqual(envelope.action.declared_artifacts, [`<slug>--pull-work.md`, "trust.bundle#selected-work"]);
|
|
379
|
+
assert.equal(envelope.stop_condition.kind, "one_turn");
|
|
380
|
+
assert.equal(envelope.stop_condition.scope.current_gate_only, true);
|
|
381
|
+
assert.deepEqual(envelope.stop_condition.required.unresolved_evidence_ids, ["selected-work"]);
|
|
382
|
+
assert.deepEqual(envelope.stop_condition.sequence, ["activate_required_skills", "produce_declared_artifacts", "record_bound_evidence", "synchronize_canonical_flow", "return_adapter_result"]);
|
|
383
|
+
assert.equal(envelope.stop_condition.adapter_evidence_is_gate_evidence, false);
|
|
384
|
+
assert.equal(envelope.action.skills[0].id, "pull-work");
|
|
385
|
+
assert.equal(envelope.action.skills[0].package.name, "@kontourai/flow-agents");
|
|
386
|
+
assert.match(envelope.action.skills[0].path, /kits\/builder\/skills\/pull-work\/SKILL\.md$/);
|
|
387
|
+
assert.match(envelope.action.skills[0].sha256, /^[a-f0-9]{64}$/);
|
|
388
|
+
assert.equal(envelope.public_interfaces.mutations[0].expectation_id, "selected-work");
|
|
389
|
+
assert.deepEqual(envelope.public_interfaces.mutations[0].package, { name: "@kontourai/flow-agents", version: PACKAGE_VERSION });
|
|
390
|
+
assert.deepEqual(envelope.public_interfaces.mutations[0].argv.slice(0, 2), ["workflow", "evidence"]);
|
|
391
|
+
assert.equal(envelope.public_interfaces.mutations[0].argv.some((value) => value.includes("<")), false, "argv contains no substitution placeholders");
|
|
366
392
|
assert.ok(fs.existsSync(runDir(session.slug, session.projectRoot)));
|
|
367
393
|
assert.ok(!fs.existsSync(path.join(session.projectRoot, ".flow", "runs")), "retired runtime path must not be created");
|
|
368
394
|
|
|
@@ -375,6 +401,8 @@ test("small-model client can start and advance from projected actions without ch
|
|
|
375
401
|
assert.equal(advanced.attached, true);
|
|
376
402
|
assert.equal(advanced.run.state.current_step, "design-probe");
|
|
377
403
|
assert.deepEqual(advanced.projection.next_action.skills, ["pickup-probe"]);
|
|
404
|
+
assert.equal(advanced.gateActionEnvelope.action.implementation_allowed, false);
|
|
405
|
+
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
406
|
assert.equal(readJson(path.join(session.artifactRoot, "current.json")).active_step_id, "design-probe");
|
|
379
407
|
|
|
380
408
|
const duplicate = await syncBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
@@ -382,6 +410,49 @@ test("small-model client can start and advance from projected actions without ch
|
|
|
382
410
|
assert.equal(duplicate.run.manifest.evidence.length, advanced.run.manifest.evidence.length);
|
|
383
411
|
});
|
|
384
412
|
|
|
413
|
+
test("gate-action implementation policy permits code only at builder.build/execute", async () => {
|
|
414
|
+
const session = makeSession("gate-action-implementation-policy");
|
|
415
|
+
await startBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
416
|
+
await writeAndSync(session, [bundleClaim({ expectation: "selected-work", claimType: "builder.pull-work.selected", subjectType: "work-item" })]);
|
|
417
|
+
await writeAndSync(session, [
|
|
418
|
+
bundleClaim({ expectation: "pickup-probe-readiness", claimType: "builder.design-probe.pickup-readiness", subjectType: "work-item" }),
|
|
419
|
+
bundleClaim({ expectation: "probe-decisions-or-accepted-gaps", claimType: "builder.design-probe.decisions", subjectType: "decision" }),
|
|
420
|
+
]);
|
|
421
|
+
const executing = await writeAndSync(session, [bundleClaim({ expectation: "implementation-plan", claimType: "builder.plan.implementation", subjectType: "artifact" })]);
|
|
422
|
+
assert.equal(executing.run.state.current_step, "execute");
|
|
423
|
+
assert.equal(executing.gateActionEnvelope.action.implementation_allowed, true);
|
|
424
|
+
assert.equal(executing.gateActionEnvelope.action.declared_artifacts.includes("state.json"), false, "control state is not a declared model artifact");
|
|
425
|
+
assert.equal(executing.gateActionEnvelope.stop_condition.required.artifact_refs.includes("state.json"), false, "control state is not a required model artifact");
|
|
426
|
+
assert.equal(executing.gateActionEnvelope.progress.observed_artifacts.some((entry) => entry.startsWith("state.json:")), false, "control state never counts as progress");
|
|
427
|
+
|
|
428
|
+
const requests = [];
|
|
429
|
+
await driveBuilderFlowSession({
|
|
430
|
+
sessionDir: session.sessionDir,
|
|
431
|
+
maxTurns: 2,
|
|
432
|
+
execute: async (request) => { requests.push(request); return { status: "completed" }; },
|
|
433
|
+
});
|
|
434
|
+
assert.equal(requests.length, 2);
|
|
435
|
+
assert.equal(requests[1].gate_action_envelope.progress.prior_turn.stagnation, "possible");
|
|
436
|
+
const mission = readJson(path.join(session.sessionDir, "continuation-driver", "state.json"));
|
|
437
|
+
assert.equal(mission.prior_progress.stagnation, "stagnant", "two no-op execute turns are true stagnation");
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
test("gate-action artifact identity reads reject symlinks and oversized files", async (t) => {
|
|
441
|
+
await t.test("symlink", async () => {
|
|
442
|
+
const session = makeSession("gate-action-artifact-symlink");
|
|
443
|
+
const outside = path.join(session.projectRoot, "outside-release.json");
|
|
444
|
+
fs.writeFileSync(outside, "{}\n");
|
|
445
|
+
fs.symlinkSync(outside, path.join(session.sessionDir, "release.json"));
|
|
446
|
+
await assert.rejects(startBuilderFlowSession({ sessionDir: session.sessionDir }), /ELOOP|regular file|changed identity/);
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
await t.test("oversized", async () => {
|
|
450
|
+
const session = makeSession("gate-action-artifact-oversized");
|
|
451
|
+
fs.writeFileSync(path.join(session.sessionDir, "release.json"), Buffer.alloc(1_048_577));
|
|
452
|
+
await assert.rejects(startBuilderFlowSession({ sessionDir: session.sessionDir }), /bounded regular file/);
|
|
453
|
+
});
|
|
454
|
+
});
|
|
455
|
+
|
|
385
456
|
test("Builder projection preserves Flow continuation semantics for exceptional statuses", async () => {
|
|
386
457
|
const session = makeSession("continuation-status-projection");
|
|
387
458
|
await startBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
@@ -399,7 +470,50 @@ test("Builder projection preserves Flow continuation semantics for exceptional s
|
|
|
399
470
|
}
|
|
400
471
|
});
|
|
401
472
|
|
|
402
|
-
test("
|
|
473
|
+
test("accepted Flow exceptions explicitly waive the current envelope requirements", async () => {
|
|
474
|
+
const session = makeSession("accepted-exception-envelope");
|
|
475
|
+
await startBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
476
|
+
const exception = await acceptException(session.slug, {
|
|
477
|
+
cwd: session.projectRoot,
|
|
478
|
+
gate: "pull-work-gate",
|
|
479
|
+
reason: "authorized fixture waiver",
|
|
480
|
+
authority: "test-reviewer",
|
|
481
|
+
});
|
|
482
|
+
const recovered = await recoverBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
483
|
+
assert.deepEqual(recovered.gateActionEnvelope.gate.accepted_exceptions, [{ gate_id: "pull-work-gate", exception_id: exception.id }]);
|
|
484
|
+
assert.equal(recovered.gateActionEnvelope.gate.requirements[0].status, "accepted_exception");
|
|
485
|
+
assert.deepEqual(recovered.gateActionEnvelope.stop_condition.required.unresolved_evidence_ids, []);
|
|
486
|
+
assert.deepEqual(recovered.gateActionEnvelope.stop_condition.required.artifact_refs, []);
|
|
487
|
+
assert.deepEqual(recovered.gateActionEnvelope.stop_condition.required.skill_ids, []);
|
|
488
|
+
const synchronized = await syncBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
489
|
+
assert.equal(synchronized.attached, false);
|
|
490
|
+
assert.equal(synchronized.run.state.current_step, "design-probe");
|
|
491
|
+
assert.deepEqual(synchronized.gateActionEnvelope.action.skills.map((skill) => skill.id), ["pickup-probe"]);
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
test("all-optional effective Flow gate overrides advance during canonical sync without bundle evidence", async () => {
|
|
495
|
+
const session = makeSession("gate-override-envelope");
|
|
496
|
+
const config = defaultFlowConfig();
|
|
497
|
+
config.gate_overrides["pull-work-gate"] = { expectations: { "selected-work": { required: false } } };
|
|
498
|
+
fs.mkdirSync(path.dirname(flowConfigPath(session.projectRoot)), { recursive: true });
|
|
499
|
+
writeJson(flowConfigPath(session.projectRoot), config);
|
|
500
|
+
const unevaluated = await startBuilderFlowRun({ cwd: session.projectRoot, runId: session.slug, subject: SUBJECT, flowId: "builder.build" });
|
|
501
|
+
const directEnvelope = deriveBuilderGateActionEnvelope({
|
|
502
|
+
sessionDir: session.sessionDir,
|
|
503
|
+
projectRoot: session.projectRoot,
|
|
504
|
+
run: unevaluated,
|
|
505
|
+
definition: readJson(path.join(unevaluated.dir, "definition.json")),
|
|
506
|
+
});
|
|
507
|
+
assert.deepEqual(directEnvelope.stop_condition.required.skill_ids, []);
|
|
508
|
+
fs.rmSync(unevaluated.dir, { recursive: true, force: true });
|
|
509
|
+
const started = await startBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
510
|
+
assert.equal(started.attached, false);
|
|
511
|
+
assert.equal(started.run.state.current_step, "design-probe");
|
|
512
|
+
assert.deepEqual(started.gateActionEnvelope.action.skills.map((skill) => skill.id), ["pickup-probe"]);
|
|
513
|
+
assert.equal(started.gateActionEnvelope.flow.current_step, "design-probe");
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
test("weak structured consumer advances real Builder gates through envelope public interfaces", async () => {
|
|
403
517
|
const session = makeSession("continuation-driver-two-steps");
|
|
404
518
|
await startBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
405
519
|
const visited = [];
|
|
@@ -409,13 +523,14 @@ test("continuation driver advances two real FlowDefinition steps unattended", as
|
|
|
409
523
|
maxTurns: 2,
|
|
410
524
|
execute: async (request) => {
|
|
411
525
|
visited.push(request.current_step);
|
|
412
|
-
|
|
526
|
+
const expectationIds = request.gate_action_envelope.public_interfaces.mutations.map((mutation) => mutation.expectation_id);
|
|
527
|
+
if (expectationIds.includes("selected-work")) {
|
|
413
528
|
writeBundle(session.sessionDir, [bundleClaim({
|
|
414
529
|
expectation: "selected-work",
|
|
415
530
|
claimType: "builder.pull-work.selected",
|
|
416
531
|
subjectType: "work-item",
|
|
417
532
|
})]);
|
|
418
|
-
} else if (
|
|
533
|
+
} else if (expectationIds.includes("pickup-probe-readiness")) {
|
|
419
534
|
writeBundle(session.sessionDir, [
|
|
420
535
|
bundleClaim({
|
|
421
536
|
expectation: "pickup-probe-readiness",
|
|
@@ -429,7 +544,7 @@ test("continuation driver advances two real FlowDefinition steps unattended", as
|
|
|
429
544
|
}),
|
|
430
545
|
]);
|
|
431
546
|
} else {
|
|
432
|
-
assert.fail(`unexpected
|
|
547
|
+
assert.fail(`unexpected public mutation set ${expectationIds.join(",")}`);
|
|
433
548
|
}
|
|
434
549
|
return { status: "completed", summary: `completed ${request.current_step}` };
|
|
435
550
|
},
|
|
@@ -478,8 +593,10 @@ test("public workflow evidence accepts only live signed turn authority after ord
|
|
|
478
593
|
const ordinaryChild = ${JSON.stringify(path.resolve(import.meta.dirname, "../../scripts/hooks/lib/actor-identity.js"))};
|
|
479
594
|
const childIdentity = (await import("node:module")).createRequire(import.meta.url)(ordinaryChild).resolveActorIdentity(evidenceEnv);
|
|
480
595
|
const record = (expectation) => {
|
|
596
|
+
const binding = request.gate_action_envelope.public_interfaces.mutations.find((entry) => entry.expectation_id === expectation && entry.interface === "workflow.evidence");
|
|
597
|
+
if (!binding) throw new Error("missing workflow.evidence binding for " + expectation);
|
|
481
598
|
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"))},
|
|
599
|
+
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
600
|
};
|
|
484
601
|
const evidenceRuns = request.current_step === "pull-work"
|
|
485
602
|
? [record("selected-work")]
|
|
@@ -556,6 +673,14 @@ test("public workflow evidence accepts only live signed turn authority after ord
|
|
|
556
673
|
assert.notEqual(forged.status, 0, "fake nonce and digest without a signed active turn fail ownership");
|
|
557
674
|
});
|
|
558
675
|
|
|
676
|
+
test("signed turn evidence capacity is rejected by preflight before another bounded result", () => {
|
|
677
|
+
assert.doesNotThrow(() => assertAcceptedTurnEvidenceCapacity([], { schema_version: "1.0", iteration: 1 }));
|
|
678
|
+
assert.throws(
|
|
679
|
+
() => assertAcceptedTurnEvidenceCapacity([{ request: { padding: "x".repeat(980_000) }, result: {} }], { schema_version: "1.0", iteration: 2 }),
|
|
680
|
+
/lacks capacity for another bounded result/,
|
|
681
|
+
);
|
|
682
|
+
});
|
|
683
|
+
|
|
559
684
|
test("public workflow drive signs adapter evidence with a consumed one-time key", async () => {
|
|
560
685
|
const session = makeSession("continuation-driver-signed-evidence");
|
|
561
686
|
claimAmbientSessionAssignment(session);
|
|
@@ -636,6 +761,8 @@ test("public workflow drive signs adapter evidence with a consumed one-time key"
|
|
|
636
761
|
assert.deepEqual(payload.adapter_turns.map((turn) => turn.request), observedRequests);
|
|
637
762
|
assert.equal(payload.adapter_turns[0].request.schema_version, "1.0");
|
|
638
763
|
assert.equal(payload.adapter_turns[0].request.next_action.status, "continue");
|
|
764
|
+
assert.equal(payload.adapter_turns[0].request.gate_action_envelope.schema_version, "1.0");
|
|
765
|
+
assert.deepEqual(payload.adapter_turns.map((turn) => turn.request), observedRequests, "the signed payload binds the unchanged envelope bytes observed by the adapter");
|
|
639
766
|
assert.deepEqual(payload.adapter_turns[0].result.evidence.usage, { input_tokens: 10, output_tokens: 2 });
|
|
640
767
|
const tampered = Buffer.from(JSON.stringify({ ...payload, max_turns: 2 }));
|
|
641
768
|
assert.equal(verify(null, tampered, keys.publicKey, Buffer.from(attestation.signature_b64, "base64")), false);
|
|
@@ -1148,6 +1275,43 @@ test("partial passing review snapshot waits for the complete verify expectation
|
|
|
1148
1275
|
assert.equal(partial.run.state.current_step, "verify");
|
|
1149
1276
|
assert.equal(partial.run.state.transitions.filter((transition) => transition.type === "route_back").length, 0);
|
|
1150
1277
|
|
|
1278
|
+
const definition = readJson(path.join(partial.run.dir, "definition.json"));
|
|
1279
|
+
const validPartialBundle = readJson(path.join(session.sessionDir, "trust.bundle"));
|
|
1280
|
+
const validPartialEvidence = {
|
|
1281
|
+
id: "partial-verify-evidence",
|
|
1282
|
+
gate_id: "verify-gate",
|
|
1283
|
+
kind: "trust.bundle",
|
|
1284
|
+
requested_kind: "trust.bundle",
|
|
1285
|
+
sha256: "a".repeat(64),
|
|
1286
|
+
status: "passed",
|
|
1287
|
+
attached_at: new Date().toISOString(),
|
|
1288
|
+
expectation_ids: ["clean-critique"],
|
|
1289
|
+
bundle: validPartialBundle,
|
|
1290
|
+
};
|
|
1291
|
+
const partialEnvelope = deriveBuilderGateActionEnvelope({
|
|
1292
|
+
sessionDir: session.sessionDir,
|
|
1293
|
+
projectRoot: session.projectRoot,
|
|
1294
|
+
run: {
|
|
1295
|
+
...partial.run,
|
|
1296
|
+
manifest: {
|
|
1297
|
+
...partial.run.manifest,
|
|
1298
|
+
evidence: [...partial.run.manifest.evidence, validPartialEvidence],
|
|
1299
|
+
},
|
|
1300
|
+
},
|
|
1301
|
+
definition,
|
|
1302
|
+
});
|
|
1303
|
+
assert.equal(partialEnvelope.gate.requirements.find((entry) => entry.id === "clean-critique").status, "satisfied");
|
|
1304
|
+
assert.deepEqual(partialEnvelope.gate.unresolved_requirement_ids.sort(), ["acceptance-criteria", "policy-compliance", "tests-evidence"]);
|
|
1305
|
+
assert.equal(partialEnvelope.gate.requirements.find((entry) => entry.id === "policy-compliance").required, false);
|
|
1306
|
+
assert.deepEqual(partialEnvelope.stop_condition.required.unresolved_evidence_ids.sort(), ["acceptance-criteria", "tests-evidence"]);
|
|
1307
|
+
assert.equal(partialEnvelope.stop_condition.required.artifact_refs.includes("trust.bundle#policy-compliance"), false);
|
|
1308
|
+
const critique = partialEnvelope.public_interfaces.mutations.find((entry) => entry.interface === "workflow.critique");
|
|
1309
|
+
assert.deepEqual(critique.parameters.find((entry) => entry.name === "verdict").allowed_values, [...WORKFLOW_CRITIQUE_STATUSES]);
|
|
1310
|
+
assert.deepEqual(critique.parameters.find((entry) => entry.name === "artifact_ref"), {
|
|
1311
|
+
name: "artifact_ref", flag: "--artifact-ref", required: false, repeatable: true,
|
|
1312
|
+
required_when: { parameter: "verdict", equals: "pass" },
|
|
1313
|
+
});
|
|
1314
|
+
|
|
1151
1315
|
const complete = await writeAndSync(session, [
|
|
1152
1316
|
bundleClaim({ expectation: "tests-evidence", claimType: "builder.verify.tests", subjectType: "flow-step" }),
|
|
1153
1317
|
...verifiedTestsPrerequisites(session),
|
|
@@ -1155,6 +1319,48 @@ test("partial passing review snapshot waits for the complete verify expectation
|
|
|
1155
1319
|
assert.equal(complete.run.state.current_step, "merge-ready");
|
|
1156
1320
|
});
|
|
1157
1321
|
|
|
1322
|
+
test("expectation_ids labels cannot satisfy a mismatched trust bundle claim", async () => {
|
|
1323
|
+
const session = makeSession("mislabeled-partial-gate");
|
|
1324
|
+
await startBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
1325
|
+
await writeAndSync(session, [bundleClaim({ expectation: "selected-work", claimType: "builder.pull-work.selected", subjectType: "work-item" })]);
|
|
1326
|
+
await writeAndSync(session, [
|
|
1327
|
+
bundleClaim({ expectation: "pickup-probe-readiness", claimType: "builder.design-probe.pickup-readiness", subjectType: "work-item" }),
|
|
1328
|
+
bundleClaim({ expectation: "probe-decisions-or-accepted-gaps", claimType: "builder.design-probe.decisions", subjectType: "decision" }),
|
|
1329
|
+
]);
|
|
1330
|
+
await writeAndSync(session, [bundleClaim({ expectation: "implementation-plan", claimType: "builder.plan.implementation", subjectType: "artifact" })]);
|
|
1331
|
+
await writeAndSync(session, [bundleClaim({ expectation: "implementation-scope", claimType: "builder.execute.scope", subjectType: "change" })]);
|
|
1332
|
+
const partial = await writeAndSync(session, verifiedTestsPrerequisites(session).slice(0, 1));
|
|
1333
|
+
|
|
1334
|
+
const mislabeledBundle = readJson(path.join(session.sessionDir, "trust.bundle"));
|
|
1335
|
+
mislabeledBundle.claims[0].claimType = "workflow.critique.wrong-claim";
|
|
1336
|
+
const definition = readJson(path.join(partial.run.dir, "definition.json"));
|
|
1337
|
+
const envelope = deriveBuilderGateActionEnvelope({
|
|
1338
|
+
sessionDir: session.sessionDir,
|
|
1339
|
+
projectRoot: session.projectRoot,
|
|
1340
|
+
run: {
|
|
1341
|
+
...partial.run,
|
|
1342
|
+
manifest: {
|
|
1343
|
+
...partial.run.manifest,
|
|
1344
|
+
evidence: [...partial.run.manifest.evidence, {
|
|
1345
|
+
id: "mislabeled-partial-verify-evidence",
|
|
1346
|
+
gate_id: "verify-gate",
|
|
1347
|
+
kind: "trust.bundle",
|
|
1348
|
+
requested_kind: "trust.bundle",
|
|
1349
|
+
sha256: "b".repeat(64),
|
|
1350
|
+
status: "passed",
|
|
1351
|
+
attached_at: new Date().toISOString(),
|
|
1352
|
+
expectation_ids: ["clean-critique"],
|
|
1353
|
+
bundle: mislabeledBundle,
|
|
1354
|
+
}],
|
|
1355
|
+
},
|
|
1356
|
+
},
|
|
1357
|
+
definition,
|
|
1358
|
+
});
|
|
1359
|
+
|
|
1360
|
+
assert.equal(envelope.gate.requirements.find((entry) => entry.id === "clean-critique").status, "unresolved");
|
|
1361
|
+
assert.equal(envelope.gate.unresolved_requirement_ids.includes("clean-critique"), true);
|
|
1362
|
+
});
|
|
1363
|
+
|
|
1158
1364
|
test("initial gate boundary rejects pre-run and far-future claims", async () => {
|
|
1159
1365
|
for (const [name, timestamp] of [
|
|
1160
1366
|
["pre-run", NOW],
|
|
@@ -1345,9 +1551,9 @@ test("workspace review fails closed when a Git worktree marker cannot be inspect
|
|
|
1345
1551
|
);
|
|
1346
1552
|
});
|
|
1347
1553
|
|
|
1348
|
-
test("
|
|
1554
|
+
test("publish-change reports an external capability gap and self-authored results cannot pass", async () => {
|
|
1349
1555
|
const session = makeSession("composed-completion");
|
|
1350
|
-
|
|
1556
|
+
const ambient = claimAmbientSessionAssignment(session);
|
|
1351
1557
|
await startBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
1352
1558
|
const steps = [
|
|
1353
1559
|
() => [bundleClaim({ expectation: "selected-work", claimType: "builder.pull-work.selected", subjectType: "work-item" })],
|
|
@@ -1367,55 +1573,78 @@ test("verified sidecar claims drive the composed publish and learning prefix to
|
|
|
1367
1573
|
assert.equal(readJson(path.join(session.artifactRoot, "current.json")).active_step_id, "pr-open");
|
|
1368
1574
|
assert.deepEqual(prOpen.next_action.skills, []);
|
|
1369
1575
|
assert.deepEqual(prOpen.next_action.operations, ["publish-change"]);
|
|
1576
|
+
assert.equal(prOpen.next_action.status, "blocked");
|
|
1577
|
+
assert.equal(prOpen.next_action.external_capability.completion, "external_verification_required");
|
|
1578
|
+
|
|
1579
|
+
const operationView = await syncBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
1580
|
+
const publish = operationView.gateActionEnvelope.public_interfaces.mutations.find((entry) => entry.interface === "operation");
|
|
1581
|
+
assert.equal(publish.operation, "publish-change");
|
|
1582
|
+
assert.equal(publish.protocol.capability, "pull_request.create");
|
|
1583
|
+
assert.deepEqual(publish.protocol.result.required, ["provider", "repository", "number", "url", "head_ref", "base_ref"]);
|
|
1584
|
+
assert.deepEqual(publish.protocol.result.properties.number, { type: "integer", minimum: 1 });
|
|
1585
|
+
assert.deepEqual(publish.protocol.result.url_protocols, ["https:"]);
|
|
1586
|
+
assert.equal(publish.protocol.result.persist_as, "publish-change.result.json");
|
|
1587
|
+
assert.deepEqual(publish.completion, {
|
|
1588
|
+
status: "external_verification_required",
|
|
1589
|
+
executable_by_flow_agents: false,
|
|
1590
|
+
gate_evidence_interface: null,
|
|
1591
|
+
});
|
|
1592
|
+
assert.equal(Object.hasOwn(publish, "record_completion"), false);
|
|
1593
|
+
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" };
|
|
1594
|
+
writeJson(path.join(session.sessionDir, publish.protocol.result.persist_as), providerResult);
|
|
1595
|
+
const unchanged = await syncBuilderFlowSession({ sessionDir: session.sessionDir });
|
|
1596
|
+
assert.equal(unchanged.attached, false);
|
|
1597
|
+
assert.equal(unchanged.run.state.current_step, "pr-open");
|
|
1598
|
+
assert.equal(unchanged.projection.next_action.status, "blocked");
|
|
1599
|
+
assert.equal(unchanged.run.manifest.evidence.some((entry) => entry.expectation_ids?.includes("pull-request-opened")), false);
|
|
1600
|
+
const beforeFlow = snapshotTree(runDir(session.slug, session.projectRoot));
|
|
1601
|
+
const beforeProjection = snapshotProjectionTargets(session);
|
|
1602
|
+
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" })];
|
|
1603
|
+
await assert.rejects(
|
|
1604
|
+
() => workflowMain(genericEvidenceArgs),
|
|
1605
|
+
/operation-bound expectation.*authenticated external ChangeProvider/,
|
|
1606
|
+
);
|
|
1607
|
+
assert.deepEqual(snapshotTree(runDir(session.slug, session.projectRoot)), beforeFlow);
|
|
1608
|
+
assert.deepEqual(snapshotProjectionTargets(session), beforeProjection);
|
|
1370
1609
|
|
|
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"),
|
|
1610
|
+
await withContinuationDriverLock(session.sessionDir, async (lock) => {
|
|
1611
|
+
const driverDir = path.join(session.sessionDir, "continuation-driver");
|
|
1612
|
+
writeJson(path.join(driverDir, "state.json"), {
|
|
1613
|
+
schema_version: "1.0", run_id: session.slug, definition_id: "builder.build", max_turns: 1,
|
|
1614
|
+
adapter_command_identity: "operation-rejection-test", status: "active", turns_started: 1,
|
|
1615
|
+
active_turn_step: "pr-open", active_turn_public_key_digest: null, pending_barrier: null,
|
|
1616
|
+
});
|
|
1617
|
+
const issued = activeTurnAuthority.issueActiveTurnAuthority({
|
|
1618
|
+
sessionDir: session.sessionDir,
|
|
1619
|
+
runId: session.slug,
|
|
1620
|
+
definitionId: "builder.build",
|
|
1621
|
+
currentStep: "pr-open",
|
|
1622
|
+
iteration: 1,
|
|
1623
|
+
maxTurns: 1,
|
|
1624
|
+
adapterCommandIdentity: "operation-rejection-test",
|
|
1625
|
+
assignmentActor: ambient.actorKey,
|
|
1626
|
+
assignmentActorStruct: ambient.actor,
|
|
1627
|
+
lock,
|
|
1628
|
+
timeoutMs: 10_000,
|
|
1629
|
+
});
|
|
1630
|
+
writeJson(path.join(driverDir, "state.json"), {
|
|
1631
|
+
...readJson(path.join(driverDir, "state.json")),
|
|
1632
|
+
active_turn_public_key_digest: issued.publicKeyDigest,
|
|
1633
|
+
});
|
|
1634
|
+
const signedEnv = {
|
|
1635
|
+
...process.env,
|
|
1636
|
+
FLOW_AGENTS_CONTINUATION_RUN_ID: issued.runId,
|
|
1637
|
+
FLOW_AGENTS_CONTINUATION_TURN_SECRET: issued.turnSecret,
|
|
1638
|
+
};
|
|
1639
|
+
for (const key of AMBIENT_IDENTITY_ENV_KEYS) delete signedEnv[key];
|
|
1640
|
+
const signed = spawnSync(process.execPath, [path.resolve(import.meta.dirname, "../../build/src/cli.js"), "workflow", ...genericEvidenceArgs], { cwd: session.projectRoot, encoding: "utf8", env: signedEnv });
|
|
1641
|
+
assert.notEqual(signed.status, 0);
|
|
1642
|
+
assert.match(signed.stderr, /operation-bound expectation.*authenticated external ChangeProvider/);
|
|
1643
|
+
assert.equal(issued.cleanup(), true);
|
|
1416
1644
|
});
|
|
1417
|
-
assert.
|
|
1418
|
-
assert.deepEqual(
|
|
1645
|
+
assert.deepEqual(snapshotTree(runDir(session.slug, session.projectRoot)), beforeFlow);
|
|
1646
|
+
assert.deepEqual(snapshotProjectionTargets(session), beforeProjection);
|
|
1647
|
+
await releaseBuilderFlowAssignment({ sessionDir: session.sessionDir, reason: `test cleanup for ${ambient.actorKey}` });
|
|
1419
1648
|
});
|
|
1420
1649
|
|
|
1421
1650
|
test("recovery loads the slug-bound run, restores every matching projection, and preserves every Flow byte", async () => {
|