@kontourai/flow-agents 3.6.0 → 3.7.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 +22 -2
- package/build/src/builder-flow-run-adapter.js +93 -28
- package/build/src/builder-flow-runtime.d.ts +8 -3
- package/build/src/builder-flow-runtime.js +308 -47
- package/build/src/cli/assignment-provider.d.ts +4 -7
- package/build/src/cli/assignment-provider.js +67 -13
- package/build/src/cli/builder-run.js +14 -18
- package/build/src/cli/workflow-sidecar.d.ts +28 -4
- package/build/src/cli/workflow-sidecar.js +801 -97
- package/build/src/cli/workflow.js +290 -42
- package/build/src/flow-kit/validate.d.ts +17 -0
- package/build/src/flow-kit/validate.js +340 -2
- package/build/src/index.js +5 -5
- package/build/src/lib/observed-command.d.ts +7 -0
- package/build/src/lib/observed-command.js +100 -0
- package/build/src/tools/generate-context-map.js +5 -3
- package/context/scripts/hooks/lib/kit-catalog.js +1 -1
- package/context/scripts/hooks/stop-goal-fit.js +78 -9
- package/docs/context-map.md +22 -20
- package/docs/developer-architecture.md +1 -1
- package/docs/public-workflow-cli.md +76 -7
- package/docs/skills-map.md +51 -27
- package/docs/spec/builder-flow-runtime.md +41 -40
- package/docs/workflow-usage-guide.md +109 -42
- package/evals/fixtures/hook-influence/cases.json +2 -2
- package/evals/integration/test_builder_entry_enforcement.sh +52 -41
- package/evals/integration/test_builder_step_producers.sh +297 -6
- package/evals/integration/test_bundle_install.sh +212 -63
- package/evals/integration/test_critique_supersession_roundtrip.sh +21 -8
- package/evals/integration/test_current_json_per_actor.sh +12 -0
- package/evals/integration/test_dual_emit_flow_step.sh +62 -43
- package/evals/integration/test_flowdef_session_activation.sh +145 -25
- package/evals/integration/test_flowdef_session_history_preservation.sh +23 -21
- package/evals/integration/test_gate_lockdown.sh +3 -5
- package/evals/integration/test_goal_fit_hook.sh +60 -2
- package/evals/integration/test_liveness_verdict.sh +14 -17
- package/evals/integration/test_phase_map_and_gate_claim.sh +63 -38
- package/evals/integration/test_public_workflow_cli.sh +325 -11
- package/evals/integration/test_pull_work_liveness_preflight.sh +22 -66
- package/evals/integration/test_sidecar_field_preservation.sh +36 -11
- package/evals/integration/test_workflow_sidecar_writer.sh +277 -44
- package/evals/integration/test_workflow_steering_hook.sh +15 -38
- package/evals/run.sh +2 -0
- package/evals/static/test_builder_skill_coherence.sh +247 -0
- package/evals/static/test_library_exports.sh +5 -2
- package/evals/static/test_workflow_skills.sh +13 -325
- package/kits/builder/flows/build.flow.json +22 -0
- package/kits/builder/flows/shape.flow.json +9 -9
- package/kits/builder/kit.json +70 -16
- package/kits/builder/skills/builder-shape/SKILL.md +75 -75
- package/kits/builder/skills/continue-work/SKILL.md +45 -106
- package/kits/builder/skills/deliver/SKILL.md +96 -442
- package/kits/builder/skills/design-probe/SKILL.md +40 -139
- package/kits/builder/skills/evidence-gate/SKILL.md +59 -201
- package/kits/builder/skills/execute-plan/SKILL.md +54 -125
- package/kits/builder/skills/fix-bug/SKILL.md +42 -132
- package/kits/builder/skills/gate-review/SKILL.md +60 -211
- package/kits/builder/skills/idea-to-backlog/SKILL.md +63 -244
- package/kits/builder/skills/learning-review/SKILL.md +63 -170
- package/kits/builder/skills/pickup-probe/SKILL.md +54 -111
- package/kits/builder/skills/plan-work/SKILL.md +51 -185
- package/kits/builder/skills/pull-work/SKILL.md +136 -485
- package/kits/builder/skills/release-readiness/SKILL.md +66 -107
- package/kits/builder/skills/review-work/SKILL.md +89 -176
- package/kits/builder/skills/tdd-workflow/SKILL.md +53 -147
- package/kits/builder/skills/verify-work/SKILL.md +101 -113
- package/package.json +2 -2
- package/scripts/hooks/lib/kit-catalog.js +1 -1
- package/scripts/hooks/stop-goal-fit.js +78 -9
- package/src/builder-flow-run-adapter.ts +118 -32
- package/src/builder-flow-runtime.ts +331 -61
- package/src/cli/assignment-provider-lock.test.mjs +83 -0
- package/src/cli/assignment-provider.ts +62 -13
- package/src/cli/builder-flow-run-adapter.test.mjs +4 -2
- package/src/cli/builder-flow-runtime.test.mjs +194 -8
- package/src/cli/builder-run.ts +3 -9
- package/src/cli/kit-metadata-security.test.mjs +232 -6
- package/src/cli/public-api.test.mjs +15 -0
- package/src/cli/workflow-sidecar-execution-proof.test.mjs +90 -0
- package/src/cli/workflow-sidecar.ts +724 -97
- package/src/cli/workflow.ts +277 -40
- package/src/flow-kit/validate.ts +320 -2
- package/src/index.ts +6 -5
- package/src/lib/observed-command.ts +96 -0
- package/src/tools/generate-context-map.ts +5 -3
|
@@ -653,26 +653,12 @@ const state = {
|
|
|
653
653
|
target_phase: "goal_fit",
|
|
654
654
|
},
|
|
655
655
|
};
|
|
656
|
-
const
|
|
657
|
-
schema_version: "1.0",
|
|
658
|
-
task_slug: "installed-hook-demo",
|
|
659
|
-
status: "fail",
|
|
660
|
-
required: true,
|
|
661
|
-
updated_at: "2026-05-09T00:01:00Z",
|
|
662
|
-
critiques: [{
|
|
663
|
-
id: "installed-hook-review",
|
|
664
|
-
reviewer: "tool-code-reviewer",
|
|
665
|
-
reviewed_at: "2026-05-09T00:01:00Z",
|
|
666
|
-
verdict: "fail",
|
|
667
|
-
summary: "Blocking installed hook verification remains.",
|
|
668
|
-
findings: [{ id: "missing-installed-exec", severity: "high", status: "open", description: "Execute the installed hook command." }],
|
|
669
|
-
}],
|
|
670
|
-
};
|
|
656
|
+
const trustBundle = { schema_version: "1.0", claims: [] };
|
|
671
657
|
function writeFixture(root) {
|
|
672
658
|
const taskDir = path.join(root, ".kontourai/flow-agents/installed-hook-demo");
|
|
673
659
|
fs.mkdirSync(taskDir, { recursive: true });
|
|
674
660
|
fs.writeFileSync(path.join(taskDir, "state.json"), JSON.stringify(state), "utf8");
|
|
675
|
-
fs.writeFileSync(path.join(taskDir, "
|
|
661
|
+
fs.writeFileSync(path.join(taskDir, "trust.bundle"), JSON.stringify(trustBundle), "utf8");
|
|
676
662
|
fs.mkdirSync(path.join(root, "docs"), { recursive: true });
|
|
677
663
|
fs.writeFileSync(path.join(root, "docs/context-map.md"), "# Context Map\n", "utf8");
|
|
678
664
|
}
|
|
@@ -704,7 +690,7 @@ function runCommand(label, command, cwd, runtimeJson) {
|
|
|
704
690
|
const ctx = runtimeJson ? (JSON.parse(result.stdout).hookSpecificOutput?.additionalContext || "") : result.stdout;
|
|
705
691
|
if (!ctx.includes("WORKFLOW STATE ATTENTION")) throw new Error(`${label} installed hook did not emit workflow attention: ${result.stdout} ${result.stderr}`);
|
|
706
692
|
if (!ctx.includes("STATE: installed-hook-demo is status:not_verified phase:verification")) throw new Error(`${label} installed hook missed state guidance: ${ctx}`);
|
|
707
|
-
if (
|
|
693
|
+
if (ctx.includes("CRITIQUE:")) throw new Error(`${label} installed hook read retired critique sidecar guidance: ${ctx}`);
|
|
708
694
|
}
|
|
709
695
|
writeFixture(claudeDest);
|
|
710
696
|
writeFixture(codexDest);
|
|
@@ -736,19 +722,12 @@ const state = {
|
|
|
736
722
|
updated_at: "2026-06-01T00:00:00Z",
|
|
737
723
|
next_action: { status: "needs_user", summary: "Opencode hook test.", target_phase: "goal_fit" },
|
|
738
724
|
};
|
|
739
|
-
const
|
|
740
|
-
schema_version: "1.0",
|
|
741
|
-
task_slug: "opencode-hook-demo",
|
|
742
|
-
status: "fail",
|
|
743
|
-
required: true,
|
|
744
|
-
updated_at: "2026-06-01T00:01:00Z",
|
|
745
|
-
critiques: [{ id: "oc-review", reviewer: "tool-code-reviewer", reviewed_at: "2026-06-01T00:01:00Z", verdict: "fail", summary: "Blocking.", findings: [{ id: "oc-open", severity: "high", status: "open", description: "Open finding." }] }],
|
|
746
|
-
};
|
|
725
|
+
const trustBundle = { schema_version: "1.0", claims: [] };
|
|
747
726
|
function writeFixture(root) {
|
|
748
727
|
const taskDir = path.join(root, ".kontourai/flow-agents/opencode-hook-demo");
|
|
749
728
|
fs.mkdirSync(taskDir, { recursive: true });
|
|
750
729
|
fs.writeFileSync(path.join(taskDir, "state.json"), JSON.stringify(state), "utf8");
|
|
751
|
-
fs.writeFileSync(path.join(taskDir, "
|
|
730
|
+
fs.writeFileSync(path.join(taskDir, "trust.bundle"), JSON.stringify(trustBundle), "utf8");
|
|
752
731
|
fs.mkdirSync(path.join(root, "docs"), { recursive: true });
|
|
753
732
|
fs.writeFileSync(path.join(root, "docs/context-map.md"), "# Context Map\n", "utf8");
|
|
754
733
|
}
|
|
@@ -767,7 +746,7 @@ function runOpencodeAdapter(bundleDest, cwd) {
|
|
|
767
746
|
const ctx = out.context || "";
|
|
768
747
|
if (!ctx.includes("WORKFLOW STATE ATTENTION")) throw new Error("opencode adapter did not emit workflow attention: stdout=" + result.stdout + " stderr=" + result.stderr);
|
|
769
748
|
if (!ctx.includes("STATE: opencode-hook-demo is status:not_verified phase:verification")) throw new Error("opencode adapter missed state guidance: " + ctx);
|
|
770
|
-
if (
|
|
749
|
+
if (ctx.includes("CRITIQUE:")) throw new Error("opencode adapter read retired critique sidecar guidance: " + ctx);
|
|
771
750
|
}
|
|
772
751
|
writeFixture(opencodeWorkspace);
|
|
773
752
|
runOpencodeAdapter(opencodeDest, opencodeWorkspace);
|
|
@@ -795,19 +774,12 @@ const state = {
|
|
|
795
774
|
updated_at: "2026-06-01T00:00:00Z",
|
|
796
775
|
next_action: { status: "needs_user", summary: "Pi hook test.", target_phase: "goal_fit" },
|
|
797
776
|
};
|
|
798
|
-
const
|
|
799
|
-
schema_version: "1.0",
|
|
800
|
-
task_slug: "pi-hook-demo",
|
|
801
|
-
status: "fail",
|
|
802
|
-
required: true,
|
|
803
|
-
updated_at: "2026-06-01T00:01:00Z",
|
|
804
|
-
critiques: [{ id: "pi-review", reviewer: "tool-code-reviewer", reviewed_at: "2026-06-01T00:01:00Z", verdict: "fail", summary: "Blocking.", findings: [{ id: "pi-open", severity: "high", status: "open", description: "Open finding." }] }],
|
|
805
|
-
};
|
|
777
|
+
const trustBundle = { schema_version: "1.0", claims: [] };
|
|
806
778
|
function writeFixture(root) {
|
|
807
779
|
const taskDir = path.join(root, ".kontourai/flow-agents/pi-hook-demo");
|
|
808
780
|
fs.mkdirSync(taskDir, { recursive: true });
|
|
809
781
|
fs.writeFileSync(path.join(taskDir, "state.json"), JSON.stringify(state), "utf8");
|
|
810
|
-
fs.writeFileSync(path.join(taskDir, "
|
|
782
|
+
fs.writeFileSync(path.join(taskDir, "trust.bundle"), JSON.stringify(trustBundle), "utf8");
|
|
811
783
|
fs.mkdirSync(path.join(root, "docs"), { recursive: true });
|
|
812
784
|
fs.writeFileSync(path.join(root, "docs/context-map.md"), "# Context Map\n", "utf8");
|
|
813
785
|
}
|
|
@@ -826,7 +798,7 @@ function runPiAdapter(bundleDest, cwd) {
|
|
|
826
798
|
const ctx = out.context || "";
|
|
827
799
|
if (!ctx.includes("WORKFLOW STATE ATTENTION")) throw new Error("pi adapter did not emit workflow attention: stdout=" + result.stdout + " stderr=" + result.stderr);
|
|
828
800
|
if (!ctx.includes("STATE: pi-hook-demo is status:not_verified phase:verification")) throw new Error("pi adapter missed state guidance: " + ctx);
|
|
829
|
-
if (
|
|
801
|
+
if (ctx.includes("CRITIQUE:")) throw new Error("pi adapter read retired critique sidecar guidance: " + ctx);
|
|
830
802
|
}
|
|
831
803
|
writeFixture(piWorkspace);
|
|
832
804
|
runPiAdapter(piDest, piWorkspace);
|
|
@@ -886,7 +858,9 @@ echo "--- Packed Package Builder Entry ---"
|
|
|
886
858
|
PACKAGE_CONSUMER="$TMPDIR_EVAL/package-consumer"
|
|
887
859
|
PACKAGE_PROJECT="$TMPDIR_EVAL/package-project"
|
|
888
860
|
PACKAGE_AMBIENT="$TMPDIR_EVAL/package-ambient"
|
|
889
|
-
mkdir -p "$PACKAGE_CONSUMER" "$PACKAGE_PROJECT/.kontourai/flow-agents" "$PACKAGE_AMBIENT/kits/builder/flows"
|
|
861
|
+
mkdir -p "$PACKAGE_CONSUMER" "$PACKAGE_PROJECT/.kontourai/flow-agents" "$PACKAGE_PROJECT/checks" "$PACKAGE_AMBIENT/kits/builder/flows"
|
|
862
|
+
printf '#!/usr/bin/env bash\nset -eu\ntest -f "$1"\nprintf "1..1\\nok 1 - session exists\\n"\n' > "$PACKAGE_PROJECT/checks/check-packed-workflow.sh"
|
|
863
|
+
chmod +x "$PACKAGE_PROJECT/checks/check-packed-workflow.sh"
|
|
890
864
|
cat >"$PACKAGE_AMBIENT/kits/builder/flows/build.flow.json" <<'JSON'
|
|
891
865
|
{
|
|
892
866
|
"id": "builder.build",
|
|
@@ -897,35 +871,152 @@ cat >"$PACKAGE_AMBIENT/kits/builder/flows/build.flow.json" <<'JSON'
|
|
|
897
871
|
JSON
|
|
898
872
|
PACKAGE_PACK_LOG="$TMPDIR_EVAL/package-pack.log"
|
|
899
873
|
PACKAGE_CLI="$PACKAGE_CONSUMER/node_modules/@kontourai/flow-agents/build/src/cli.js"
|
|
900
|
-
PACKAGE_SESSION="$PACKAGE_PROJECT/.kontourai/flow-agents/
|
|
874
|
+
PACKAGE_SESSION="$PACKAGE_PROJECT/.kontourai/flow-agents/acme-builder-901"
|
|
875
|
+
PACKAGE_LIFECYCLE_SESSION="$PACKAGE_PROJECT/.kontourai/flow-agents/acme-builder-902"
|
|
876
|
+
PACKAGE_TEST_COMMAND="bash checks/check-packed-workflow.sh .kontourai/flow-agents/acme-builder-901/state.json"
|
|
877
|
+
PACKAGE_CRITERION_JSON="$(node - "$PACKAGE_TEST_COMMAND" <<'NODE'
|
|
878
|
+
const command = process.argv[2];
|
|
879
|
+
process.stdout.write(JSON.stringify({
|
|
880
|
+
id: 'AC-1',
|
|
881
|
+
status: 'pass',
|
|
882
|
+
evidence_refs: [{ kind: 'command', excerpt: command, summary: 'The packed public workflow fixture executed this exact assertion for AC-1.' }],
|
|
883
|
+
}));
|
|
884
|
+
NODE
|
|
885
|
+
)"
|
|
886
|
+
PACKAGE_COMMAND_REF="$(node - "$PACKAGE_TEST_COMMAND" <<'NODE'
|
|
887
|
+
const command = process.argv[2];
|
|
888
|
+
process.stdout.write(JSON.stringify({ kind: 'command', excerpt: command, summary: 'Runs the packed consumer workflow assertion.' }));
|
|
889
|
+
NODE
|
|
890
|
+
)"
|
|
891
|
+
|
|
892
|
+
package_flow() {
|
|
893
|
+
(cd "$PACKAGE_PROJECT" && CODEX_SESSION_ID=packed-package-consumer node "$PACKAGE_CLI" workflow "$@")
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
package_review() {
|
|
897
|
+
(cd "$PACKAGE_PROJECT" && CODEX_SESSION_ID=packed-package-reviewer node "$PACKAGE_CLI" workflow "$@")
|
|
898
|
+
}
|
|
899
|
+
|
|
901
900
|
if (cd "$ROOT_DIR" && npm pack --silent --pack-destination "$TMPDIR_EVAL" >"$PACKAGE_PACK_LOG") \
|
|
902
901
|
&& PACKAGE_TARBALL="$(find "$TMPDIR_EVAL" -maxdepth 1 -type f -name 'kontourai-flow-agents-*.tgz' -print -quit)" \
|
|
903
902
|
&& [[ -n "$PACKAGE_TARBALL" ]] \
|
|
904
903
|
&& npm install --silent --no-audit --no-fund --ignore-scripts --prefix "$PACKAGE_CONSUMER" "$PACKAGE_TARBALL" \
|
|
905
|
-
&&
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
--
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
904
|
+
&& mkdir -p "$PACKAGE_SESSION" "$PACKAGE_LIFECYCLE_SESSION" \
|
|
905
|
+
&& printf 'Selected Work Item: acme/builder#901\n' > "$PACKAGE_SESSION/acme-builder-901--pull-work.md" \
|
|
906
|
+
&& package_flow start --artifact-root "$PACKAGE_PROJECT/.kontourai/flow-agents" \
|
|
907
|
+
--flow builder.build --work-item acme/builder#901 --assignment-provider local-file --summary "Packed public workflow contract fixture." >/dev/null \
|
|
908
|
+
&& node - "$PACKAGE_SESSION" <<'NODE' &&
|
|
909
|
+
const fs = require('node:fs');
|
|
910
|
+
const path = require('node:path');
|
|
911
|
+
const session = process.argv[2];
|
|
912
|
+
const slug = path.basename(session);
|
|
913
|
+
const write = (name, body) => fs.writeFileSync(path.join(session, name), body, 'utf8');
|
|
914
|
+
write(`${slug}--pull-work.md`, '# Pull And Probe Report\n\nSelected Work Item: acme/builder#901\n\nPickup readiness and recorded decisions are reviewable here.\n');
|
|
915
|
+
write(`${slug}--plan-work.md`, '# Plan\n\n## Definition Of Done\n\n- AC-1: The packed workflow fixture records criterion-backed command evidence.\n');
|
|
916
|
+
write(`${slug}--deliver.md`, '# Execute\n\nThe packed fixture changed only its declared fixture artifacts.\n');
|
|
917
|
+
write(`${slug}--evidence-gate.md`, '# Evidence Gate\n\nScope and acceptance coverage are reviewable here.\n');
|
|
918
|
+
write('acceptance.json', JSON.stringify({ schema_version: '1.0', task_slug: slug, criteria: [{ id: 'AC-1', description: 'The packed workflow fixture records criterion-backed command evidence.', status: 'pending', evidence_refs: [] }], goal_fit: { status: 'pending', summary: 'Fixture has not completed Goal Fit review.' } }, null, 2));
|
|
919
|
+
write('release.json', JSON.stringify({ schema_version: '1.0', task_slug: slug, decision: 'hold', updated_at: '2026-07-11T00:00:00Z', scope: 'packed fixture', evidence_ref: `${slug}--evidence-gate.md`, gates: [{ name: 'merge', status: 'hold', summary: 'Fixture never publishes.' }], rollback_plan: { status: 'not_required', summary: 'No release.', owner: 'fixture' }, observability_plan: { status: 'not_required', summary: 'No release.' }, post_deploy_checks: [], docs: { status: 'not_needed', summary: 'Fixture.' } }, null, 2));
|
|
920
|
+
write('learning.json', JSON.stringify({ schema_version: '1.0', task_slug: slug, status: 'learned', updated_at: '2026-07-11T00:00:00Z', records: [{ id: 'packed-fixture-learning', recorded_at: '2026-07-11T00:00:00Z', source_refs: [`${slug}--evidence-gate.md`], outcome: 'success', facts: ['Packed consumer produced declared durable artifacts.'], interpretation: 'The public workflow contract remained usable after npm install.', routing: [{ target: 'none', action: 'No follow-up required.', status: 'completed' }], correction: { needed: false, evidence: 'Fixture contract passes.' } }] }, null, 2));
|
|
921
|
+
NODE
|
|
922
|
+
node - "$PACKAGE_PROJECT" <<'NODE' &&
|
|
912
923
|
const fs = require('node:fs');
|
|
913
924
|
const path = require('node:path');
|
|
914
925
|
const project = process.argv[2];
|
|
915
|
-
const state = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow-agents', '
|
|
916
|
-
const flow = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow', 'runs', '
|
|
917
|
-
const bundle = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow-agents', '
|
|
926
|
+
const state = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow-agents', 'acme-builder-901', 'state.json'), 'utf8'));
|
|
927
|
+
const flow = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow', 'runs', 'acme-builder-901', 'state.json'), 'utf8'));
|
|
928
|
+
const bundle = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow-agents', 'acme-builder-901', 'trust.bundle'), 'utf8'));
|
|
918
929
|
if (flow.current_step !== 'design-probe' || state.flow_run?.current_step !== 'design-probe') process.exit(1);
|
|
919
930
|
if (JSON.stringify(state.next_action?.skills) !== JSON.stringify(['pickup-probe'])) process.exit(1);
|
|
920
931
|
if (!(bundle.claims || []).some((claim) => claim.claimType === 'builder.pull-work.selected' && claim.status === 'verified')) process.exit(1);
|
|
921
932
|
NODE
|
|
922
|
-
|
|
933
|
+
package_flow evidence --session-dir "$PACKAGE_SESSION" --expectation pickup-probe-readiness --status pass \
|
|
934
|
+
--summary "Packed fixture records the declared pickup readiness artifact." \
|
|
935
|
+
--evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$PACKAGE_SESSION/acme-builder-901--pull-work.md\",\"summary\":\"Durable pickup readiness artifact.\"}" >/dev/null \
|
|
936
|
+
&& package_flow evidence --session-dir "$PACKAGE_SESSION" --expectation probe-decisions-or-accepted-gaps --status pass \
|
|
937
|
+
--summary "Packed fixture records the declared probe decisions artifact." \
|
|
938
|
+
--evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$PACKAGE_SESSION/acme-builder-901--pull-work.md\",\"summary\":\"Durable probe decisions artifact.\"}" >/dev/null \
|
|
939
|
+
&& package_flow evidence --session-dir "$PACKAGE_SESSION" --expectation implementation-plan --status pass \
|
|
940
|
+
--summary "Packed fixture records the declared implementation plan artifact." \
|
|
941
|
+
--evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$PACKAGE_SESSION/acme-builder-901--plan-work.md\",\"summary\":\"Durable implementation plan artifact.\"}" >/dev/null \
|
|
942
|
+
&& package_flow evidence --session-dir "$PACKAGE_SESSION" --expectation implementation-scope --status pass \
|
|
943
|
+
--summary "Packed fixture records the declared execution scope artifact." \
|
|
944
|
+
--evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$PACKAGE_SESSION/acme-builder-901--deliver.md\",\"summary\":\"Durable execution scope artifact.\"}" >/dev/null \
|
|
945
|
+
&& ! package_flow evidence --session-dir "$PACKAGE_SESSION" --expectation tests-evidence --status pass \
|
|
946
|
+
--command "$PACKAGE_TEST_COMMAND" --criterion-json "$PACKAGE_CRITERION_JSON" \
|
|
947
|
+
--summary "This must reject tests evidence before a clean review." \
|
|
948
|
+
--evidence-ref-json "$PACKAGE_COMMAND_REF" >/dev/null 2>&1 \
|
|
949
|
+
&& package_review critique --session-dir "$PACKAGE_SESSION" --verdict pass \
|
|
950
|
+
--summary "Authenticated packed review found no blocking fixture findings." \
|
|
951
|
+
--artifact-ref "$PACKAGE_SESSION/acme-builder-901--deliver.md" \
|
|
952
|
+
--lane-json "{\"id\":\"code-review\",\"status\":\"pass\",\"summary\":\"Reviewed the packed consumer delivery.\",\"evidence_refs\":[{\"kind\":\"artifact\",\"file\":\"$PACKAGE_SESSION/acme-builder-901--deliver.md\",\"summary\":\"Reviewed packed delivery artifact.\"}]}" >/dev/null \
|
|
953
|
+
&& package_flow evidence --session-dir "$PACKAGE_SESSION" --expectation tests-evidence --status pass \
|
|
954
|
+
--command "$PACKAGE_TEST_COMMAND" --criterion-json "$PACKAGE_CRITERION_JSON" \
|
|
955
|
+
--summary "Packed fixture records criterion-backed command evidence after review." \
|
|
956
|
+
--evidence-ref-json "$PACKAGE_COMMAND_REF" >/dev/null \
|
|
957
|
+
&& node - "$PACKAGE_SESSION" <<'NODE' &&
|
|
958
|
+
const fs = require('node:fs');
|
|
959
|
+
const path = require('node:path');
|
|
960
|
+
const session = process.argv[2];
|
|
961
|
+
const bundle = JSON.parse(fs.readFileSync(path.join(session, 'trust.bundle'), 'utf8'));
|
|
962
|
+
const criterionClaim = (bundle.claims || []).find((claim) =>
|
|
963
|
+
claim.metadata?.origin === 'acceptance'
|
|
964
|
+
&& claim.metadata?.criterion?.id === 'AC-1'
|
|
965
|
+
&& claim.metadata.criterion.status === 'pass'
|
|
966
|
+
&& claim.metadata.criterion.evidence_refs?.some((ref) => ref.kind === 'command'));
|
|
967
|
+
if (!criterionClaim) {
|
|
968
|
+
console.error('AC-1 is missing criterion-backed command evidence');
|
|
969
|
+
process.exit(1);
|
|
970
|
+
}
|
|
971
|
+
NODE
|
|
972
|
+
package_flow evidence --session-dir "$PACKAGE_SESSION" --expectation merge-readiness --status pass \
|
|
973
|
+
--summary "Packed fixture records the declared merge-readiness artifact." \
|
|
974
|
+
--evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$PACKAGE_SESSION/acme-builder-901--evidence-gate.md\",\"summary\":\"Durable merge-readiness artifact.\"}" >/dev/null \
|
|
975
|
+
&& package_flow evidence --session-dir "$PACKAGE_SESSION" --expectation pull-request-opened --status pass \
|
|
976
|
+
--summary "Packed fixture records the declared release artifact." \
|
|
977
|
+
--evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$PACKAGE_SESSION/release.json\",\"summary\":\"Durable release artifact.\"}" >/dev/null \
|
|
978
|
+
&& package_flow evidence --session-dir "$PACKAGE_SESSION" --expectation ci-merge-readiness --status pass \
|
|
979
|
+
--summary "Packed fixture records the declared CI readiness artifact." \
|
|
980
|
+
--evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$PACKAGE_SESSION/release.json\",\"summary\":\"Durable CI readiness artifact.\"}" >/dev/null \
|
|
981
|
+
&& package_flow evidence --session-dir "$PACKAGE_SESSION" --expectation decision-evidence --status pass \
|
|
982
|
+
--summary "Packed fixture records the declared learning decision artifact." \
|
|
983
|
+
--evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$PACKAGE_SESSION/learning.json\",\"summary\":\"Durable learning decision artifact.\"}" >/dev/null \
|
|
984
|
+
&& package_flow evidence --session-dir "$PACKAGE_SESSION" --expectation learning-evidence --status pass \
|
|
985
|
+
--summary "Packed fixture records the declared learning evidence artifact." \
|
|
986
|
+
--evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$PACKAGE_SESSION/learning.json\",\"summary\":\"Durable learning evidence artifact.\"}" >/dev/null \
|
|
987
|
+
&& node - "$PACKAGE_SESSION" <<'NODE' &&
|
|
988
|
+
const fs = require('node:fs');
|
|
989
|
+
const path = require('node:path');
|
|
990
|
+
const session = process.argv[2];
|
|
991
|
+
const bundle = JSON.parse(fs.readFileSync(path.join(session, 'trust.bundle'), 'utf8'));
|
|
992
|
+
const types = new Set((bundle.claims || []).filter((claim) => claim.status === 'verified').map((claim) => claim.claimType));
|
|
993
|
+
const requiredTypes = [
|
|
994
|
+
'builder.pull-work.selected',
|
|
995
|
+
'builder.design-probe.pickup-readiness',
|
|
996
|
+
'builder.design-probe.decisions',
|
|
997
|
+
'builder.plan.implementation',
|
|
998
|
+
'builder.execute.scope',
|
|
999
|
+
'builder.verify.tests',
|
|
1000
|
+
'builder.merge-ready.readiness',
|
|
1001
|
+
'builder.learn.decisions',
|
|
1002
|
+
'builder.learn.evidence',
|
|
1003
|
+
];
|
|
1004
|
+
const missingTypes = requiredTypes.filter((type) => !types.has(type));
|
|
1005
|
+
if (missingTypes.length > 0) {
|
|
1006
|
+
console.error(`missing verified public workflow claims: ${missingTypes.join(', ')}`);
|
|
1007
|
+
process.exit(1);
|
|
1008
|
+
}
|
|
1009
|
+
NODE
|
|
1010
|
+
printf 'Selected Work Item: acme/builder#902\n' > "$PACKAGE_LIFECYCLE_SESSION/acme-builder-902--pull-work.md" \
|
|
1011
|
+
&& package_flow start --artifact-root "$PACKAGE_PROJECT/.kontourai/flow-agents" \
|
|
1012
|
+
--flow builder.build --work-item acme/builder#902 --assignment-provider local-file --summary "Packed public lifecycle fixture." >/dev/null \
|
|
1013
|
+
&& node --input-type=module - "$PACKAGE_PROJECT" "$PACKAGE_LIFECYCLE_SESSION" "$PACKAGE_CONSUMER" <<'NODE' &&
|
|
923
1014
|
import fs from 'node:fs';
|
|
924
1015
|
import path from 'node:path';
|
|
925
1016
|
import { generateKeyPairSync, sign } from 'node:crypto';
|
|
926
1017
|
import { pathToFileURL } from 'node:url';
|
|
927
|
-
const [project, consumer] = process.argv.slice(2);
|
|
928
|
-
const slug =
|
|
1018
|
+
const [project, session, consumer] = process.argv.slice(2);
|
|
1019
|
+
const slug = path.basename(session);
|
|
929
1020
|
const assignment = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow-agents', 'assignment', `${slug}.json`), 'utf8'));
|
|
930
1021
|
const state = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow-agents', slug, 'state.json'), 'utf8'));
|
|
931
1022
|
const packageEntry = path.join(consumer, 'node_modules', '@kontourai', 'flow-agents', 'build', 'src', 'index.js');
|
|
@@ -957,15 +1048,15 @@ for (const operation of ['cancel', 'archive']) {
|
|
|
957
1048
|
fs.writeFileSync(path.join(project, `${operation}.authorization.json`), JSON.stringify(authorization, null, 2));
|
|
958
1049
|
}
|
|
959
1050
|
NODE
|
|
960
|
-
|
|
961
|
-
&&
|
|
962
|
-
&&
|
|
963
|
-
&&
|
|
1051
|
+
package_flow pause --session-dir "$PACKAGE_LIFECYCLE_SESSION" --reason "packed pause" >/dev/null \
|
|
1052
|
+
&& package_flow resume --session-dir "$PACKAGE_LIFECYCLE_SESSION" --reason "packed resume" >/dev/null \
|
|
1053
|
+
&& package_flow cancel --session-dir "$PACKAGE_LIFECYCLE_SESSION" --authorization-file "$PACKAGE_PROJECT/cancel.authorization.json" >/dev/null \
|
|
1054
|
+
&& package_flow archive --session-dir "$PACKAGE_LIFECYCLE_SESSION" --authorization-file "$PACKAGE_PROJECT/archive.authorization.json" >/dev/null \
|
|
964
1055
|
&& node - "$PACKAGE_PROJECT" <<'NODE'
|
|
965
1056
|
const fs = require('node:fs');
|
|
966
1057
|
const path = require('node:path');
|
|
967
1058
|
const project = process.argv[2];
|
|
968
|
-
const slug = '
|
|
1059
|
+
const slug = 'acme-builder-902';
|
|
969
1060
|
const archived = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow-agents', 'archive', slug, 'state.json'), 'utf8'));
|
|
970
1061
|
const flow = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow', 'runs', slug, 'state.json'), 'utf8'));
|
|
971
1062
|
const consumed = fs.readdirSync(path.join(project, '.kontourai', 'flow-agents', 'lifecycle-authority', 'consumed'));
|
|
@@ -973,13 +1064,42 @@ if (archived.status !== 'archived' || flow.status !== 'canceled' || consumed.len
|
|
|
973
1064
|
if (fs.existsSync(path.join(project, '.kontourai', 'flow-agents', slug))) process.exit(1);
|
|
974
1065
|
NODE
|
|
975
1066
|
then
|
|
976
|
-
_pass "packed npm consumer
|
|
1067
|
+
_pass "packed npm consumer follows the public Builder workflow contract and lifecycle commands"
|
|
977
1068
|
else
|
|
978
|
-
_fail "packed npm consumer did not
|
|
1069
|
+
_fail "packed npm consumer did not complete the public Builder workflow contract and lifecycle commands"
|
|
979
1070
|
fi
|
|
980
1071
|
|
|
981
|
-
if
|
|
982
|
-
|
|
1072
|
+
if node - "$CODEX_FULL_DEST/.codex/skills" "$CODEX_FULL_DEST" <<'NODE'
|
|
1073
|
+
const fs = require('node:fs');
|
|
1074
|
+
const path = require('node:path');
|
|
1075
|
+
const [root, installRoot] = process.argv.slice(2);
|
|
1076
|
+
const builder = [
|
|
1077
|
+
'builder-shape', 'continue-work', 'deliver', 'design-probe', 'evidence-gate',
|
|
1078
|
+
'execute-plan', 'fix-bug', 'gate-review', 'idea-to-backlog', 'learning-review',
|
|
1079
|
+
'pickup-probe', 'plan-work', 'pull-work', 'release-readiness', 'review-work',
|
|
1080
|
+
'tdd-workflow', 'verify-work',
|
|
1081
|
+
];
|
|
1082
|
+
for (const skill of [...builder, 'agentic-engineering']) {
|
|
1083
|
+
const file = path.join(root, skill, 'SKILL.md');
|
|
1084
|
+
if (!fs.existsSync(file)) throw new Error(`missing installed skill ${skill}`);
|
|
1085
|
+
if (builder.includes(skill)) {
|
|
1086
|
+
const text = fs.readFileSync(file, 'utf8');
|
|
1087
|
+
if (/npm run workflow:sidecar|flow-agents-workflow-sidecar|flow-agents builder-run/.test(text)) {
|
|
1088
|
+
throw new Error(`${skill} exposes a private workflow command`);
|
|
1089
|
+
}
|
|
1090
|
+
if (/--reviewer/.test(text)) {
|
|
1091
|
+
throw new Error(`${skill} exposes a caller-selected review identity`);
|
|
1092
|
+
}
|
|
1093
|
+
if (skill === 'verify-work' && (!/--criterion-json/.test(text) || /--command\s+"(?:true|node --version)"/.test(text))) {
|
|
1094
|
+
throw new Error('verify-work must ship criterion-backed substantive verification evidence guidance');
|
|
1095
|
+
}
|
|
1096
|
+
const refs = [...text.matchAll(/\b(?:context|docs|kits)\/[A-Za-z0-9_./-]+\.(?:md|json)\b/g)].map((match) => match[0]);
|
|
1097
|
+
for (const ref of refs) if (!fs.existsSync(path.join(installRoot, ref))) throw new Error(`${skill} has unresolved installed resource ${ref}`);
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
NODE
|
|
1101
|
+
then
|
|
1102
|
+
_pass "Codex full install ships all 17 coherent Builder skills and standalone skills"
|
|
983
1103
|
else
|
|
984
1104
|
_fail "Codex full install is missing skills"
|
|
985
1105
|
fi
|
|
@@ -997,8 +1117,37 @@ else
|
|
|
997
1117
|
_fail "opencode full install is missing base agents"
|
|
998
1118
|
fi
|
|
999
1119
|
|
|
1000
|
-
if
|
|
1001
|
-
|
|
1120
|
+
if node - "$OPENCODE_FULL_DEST/.opencode/skills" "$OPENCODE_FULL_DEST" <<'NODE'
|
|
1121
|
+
const fs = require('node:fs');
|
|
1122
|
+
const path = require('node:path');
|
|
1123
|
+
const [root, installRoot] = process.argv.slice(2);
|
|
1124
|
+
const builder = [
|
|
1125
|
+
'builder-shape', 'continue-work', 'deliver', 'design-probe', 'evidence-gate',
|
|
1126
|
+
'execute-plan', 'fix-bug', 'gate-review', 'idea-to-backlog', 'learning-review',
|
|
1127
|
+
'pickup-probe', 'plan-work', 'pull-work', 'release-readiness', 'review-work',
|
|
1128
|
+
'tdd-workflow', 'verify-work',
|
|
1129
|
+
];
|
|
1130
|
+
for (const skill of [...builder, 'agentic-engineering']) {
|
|
1131
|
+
const file = path.join(root, skill, 'SKILL.md');
|
|
1132
|
+
if (!fs.existsSync(file)) throw new Error(`missing installed skill ${skill}`);
|
|
1133
|
+
if (builder.includes(skill)) {
|
|
1134
|
+
const text = fs.readFileSync(file, 'utf8');
|
|
1135
|
+
if (/npm run workflow:sidecar|flow-agents-workflow-sidecar|flow-agents builder-run/.test(text)) {
|
|
1136
|
+
throw new Error(`${skill} exposes a private workflow command`);
|
|
1137
|
+
}
|
|
1138
|
+
if (/--reviewer/.test(text)) {
|
|
1139
|
+
throw new Error(`${skill} exposes a caller-selected review identity`);
|
|
1140
|
+
}
|
|
1141
|
+
if (skill === 'verify-work' && (!/--criterion-json/.test(text) || /--command\s+"(?:true|node --version)"/.test(text))) {
|
|
1142
|
+
throw new Error('verify-work must ship criterion-backed substantive verification evidence guidance');
|
|
1143
|
+
}
|
|
1144
|
+
const refs = [...text.matchAll(/\b(?:context|docs|kits)\/[A-Za-z0-9_./-]+\.(?:md|json)\b/g)].map((match) => match[0]);
|
|
1145
|
+
for (const ref of refs) if (!fs.existsSync(path.join(installRoot, ref))) throw new Error(`${skill} has unresolved installed resource ${ref}`);
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
NODE
|
|
1149
|
+
then
|
|
1150
|
+
_pass "opencode full install ships all 17 coherent Builder skills and standalone skills"
|
|
1002
1151
|
else
|
|
1003
1152
|
_fail "opencode full install is missing skills"
|
|
1004
1153
|
fi
|
|
@@ -48,15 +48,20 @@ seed() {
|
|
|
48
48
|
# ─── (a) same-reviewer supersession: fail → pass ──────────────────────────────
|
|
49
49
|
echo ""
|
|
50
50
|
echo "=== (a) record-critique fail→pass (same reviewer) supersedes, history intact, reconcile 0 ==="
|
|
51
|
-
A_AROOT="$TMP/a/
|
|
51
|
+
A_AROOT="$TMP/a/.kontourai/flow-agents"; A_SLUG="supersede-same"; A_DIR="$A_AROOT/$A_SLUG"
|
|
52
52
|
seed "$A_AROOT" "$A_SLUG"
|
|
53
53
|
flow_agents_node "$WRITER" record-evidence "$A_DIR" --verdict pass \
|
|
54
54
|
--check-json '{"id":"c1","kind":"diff","status":"pass","summary":"diff check"}' \
|
|
55
55
|
--timestamp "2026-07-01T00:01:00Z" >/dev/null 2>&1
|
|
56
56
|
flow_agents_node "$WRITER" record-critique "$A_DIR" --id rv --reviewer alice --verdict fail \
|
|
57
|
-
--summary "found a bug"
|
|
57
|
+
--summary "found a bug" \
|
|
58
|
+
--lane-json "{\"id\":\"code\",\"status\":\"fail\",\"summary\":\"bug found\",\"evidence_refs\":[{\"kind\":\"artifact\",\"file\":\"$A_DIR/$A_SLUG--deliver.md\",\"summary\":\"Reviewed the failing delivery artifact.\"}]}" \
|
|
59
|
+
--timestamp "2026-07-01T00:02:00Z" >/dev/null 2>&1
|
|
58
60
|
flow_agents_node "$WRITER" record-critique "$A_DIR" --id rv --reviewer alice --verdict pass \
|
|
59
|
-
--summary "bug fixed"
|
|
61
|
+
--summary "bug fixed" \
|
|
62
|
+
--lane-json "{\"id\":\"code\",\"status\":\"pass\",\"summary\":\"fix verified\",\"evidence_refs\":[{\"kind\":\"artifact\",\"file\":\"$A_DIR/$A_SLUG--deliver.md\",\"summary\":\"Reviewed the corrected delivery artifact.\"}]}" \
|
|
63
|
+
--artifact-ref "$A_DIR/$A_SLUG--deliver.md" \
|
|
64
|
+
--timestamp "2026-07-01T00:03:00Z" >/dev/null 2>&1
|
|
60
65
|
|
|
61
66
|
node - "$A_DIR/trust.bundle" << 'NODE'
|
|
62
67
|
const fs = require('fs');
|
|
@@ -80,7 +85,7 @@ if [[ $? -eq 0 ]]; then _pass "(a) trust-reconcile exits 0 (resolved session con
|
|
|
80
85
|
# ─── (b) HEADLINE: --flow-id session converges ────────────────────────────────
|
|
81
86
|
echo ""
|
|
82
87
|
echo "=== (b) HEADLINE --flow-id builder.build/verify: mixed evidence + critique → reconcile 0 ==="
|
|
83
|
-
B_AROOT="$TMP/b/
|
|
88
|
+
B_AROOT="$TMP/b/.kontourai/flow-agents"; B_SLUG="flowid-converge"; B_DIR="$B_AROOT/$B_SLUG"
|
|
84
89
|
seed "$B_AROOT" "$B_SLUG" --flow-id builder.build
|
|
85
90
|
flow_agents_node "$WRITER" advance-state "$B_DIR" --status in_progress --phase verification \
|
|
86
91
|
--summary "Testing at verify." --next-action "Record evidence." \
|
|
@@ -91,7 +96,10 @@ flow_agents_node "$WRITER" record-evidence "$B_DIR" --verdict pass \
|
|
|
91
96
|
--check-json '{"id":"k-ext","kind":"external","status":"pass","summary":"attested"}' \
|
|
92
97
|
--timestamp "2026-07-01T00:01:00Z" >/dev/null 2>&1
|
|
93
98
|
flow_agents_node "$WRITER" record-critique "$B_DIR" --id code-review --reviewer alice --verdict pass \
|
|
94
|
-
--summary "looks good"
|
|
99
|
+
--summary "looks good" \
|
|
100
|
+
--lane-json "{\"id\":\"code\",\"status\":\"pass\",\"summary\":\"review passed\",\"evidence_refs\":[{\"kind\":\"artifact\",\"file\":\"$B_DIR/$B_SLUG--deliver.md\",\"summary\":\"Reviewed the delivery artifact.\"}]}" \
|
|
101
|
+
--artifact-ref "$B_DIR/$B_SLUG--deliver.md" \
|
|
102
|
+
--timestamp "2026-07-01T00:02:00Z" >/dev/null 2>&1
|
|
95
103
|
|
|
96
104
|
node - "$B_DIR/trust.bundle" << 'NODE'
|
|
97
105
|
const fs = require('fs');
|
|
@@ -132,15 +140,20 @@ if [[ $? -eq 0 ]]; then _pass "(c) critique history survives a later record-evid
|
|
|
132
140
|
# ─── (d) ANTI-GAMING: cross-reviewer cannot supersede a reviewer fail ─────────
|
|
133
141
|
echo ""
|
|
134
142
|
echo "=== (d) ANTI-GAMING: a different reviewer cannot supersede a reviewer's fail ==="
|
|
135
|
-
D_AROOT="$TMP/d/
|
|
143
|
+
D_AROOT="$TMP/d/.kontourai/flow-agents"; D_SLUG="supersede-cross"; D_DIR="$D_AROOT/$D_SLUG"
|
|
136
144
|
seed "$D_AROOT" "$D_SLUG"
|
|
137
145
|
flow_agents_node "$WRITER" record-evidence "$D_DIR" --verdict pass \
|
|
138
146
|
--check-json '{"id":"c1","kind":"diff","status":"pass","summary":"diff check"}' \
|
|
139
147
|
--timestamp "2026-07-01T00:01:00Z" >/dev/null 2>&1
|
|
140
148
|
flow_agents_node "$WRITER" record-critique "$D_DIR" --id rv --reviewer reviewer-bob --verdict fail \
|
|
141
|
-
--summary "reviewer found a real bug"
|
|
149
|
+
--summary "reviewer found a real bug" \
|
|
150
|
+
--lane-json "{\"id\":\"code\",\"status\":\"fail\",\"summary\":\"bug found\",\"evidence_refs\":[{\"kind\":\"artifact\",\"file\":\"$D_DIR/$D_SLUG--deliver.md\",\"summary\":\"Reviewed the failing delivery artifact.\"}]}" \
|
|
151
|
+
--timestamp "2026-07-01T00:02:00Z" >/dev/null 2>&1
|
|
142
152
|
flow_agents_node "$WRITER" record-critique "$D_DIR" --id rv --reviewer worker-mallory --verdict pass \
|
|
143
|
-
--summary "worker claims fixed"
|
|
153
|
+
--summary "worker claims fixed" \
|
|
154
|
+
--lane-json "{\"id\":\"code\",\"status\":\"pass\",\"summary\":\"worker claims review passed\",\"evidence_refs\":[{\"kind\":\"artifact\",\"file\":\"$D_DIR/$D_SLUG--deliver.md\",\"summary\":\"Reviewed the claimed correction.\"}]}" \
|
|
155
|
+
--artifact-ref "$D_DIR/$D_SLUG--deliver.md" \
|
|
156
|
+
--timestamp "2026-07-01T00:03:00Z" >/dev/null 2>&1
|
|
144
157
|
node - "$D_DIR/trust.bundle" << 'NODE'
|
|
145
158
|
const fs = require('fs');
|
|
146
159
|
const b = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
|
|
@@ -371,6 +371,7 @@ set -e
|
|
|
371
371
|
echo "--- 5. record-gate-claim resolves A's own per-actor flow/step, not B's legacy pointer (AC11) ---"
|
|
372
372
|
|
|
373
373
|
AC11_ROOT="$TMPDIR_EVAL/ac11-project/.kontourai/flow-agents"
|
|
374
|
+
AC11_WORK_ITEM="local:gate-actor-a"
|
|
374
375
|
|
|
375
376
|
flow_agents_node "workflow-sidecar" ensure-session \
|
|
376
377
|
--artifact-root "$AC11_ROOT" \
|
|
@@ -388,6 +389,16 @@ flow_agents_node "workflow-sidecar" init-plan "$AC11_DELIVER_MD" \
|
|
|
388
389
|
--source-request "Test" --summary "Testing" \
|
|
389
390
|
--timestamp "2026-07-01T00:00:30Z" >"$TMPDIR_EVAL/ac11-a-initplan.out" 2>"$TMPDIR_EVAL/ac11-a-initplan.err"
|
|
390
391
|
|
|
392
|
+
# A passing selected-work claim must cite pull-work's declared durable artifact. Keep it in A's
|
|
393
|
+
# session so the generic producer/evidence contract is exercised without weakening AC11's
|
|
394
|
+
# per-actor pointer differential.
|
|
395
|
+
AC11_PULL_WORK_ARTIFACT="$AC11_ROOT/gate-actor-a/gate-actor-a--pull-work.md"
|
|
396
|
+
safe_write "$AC11_PULL_WORK_ARTIFACT" <<EOF
|
|
397
|
+
# Pull Work
|
|
398
|
+
|
|
399
|
+
Selected Work Item: $AC11_WORK_ITEM
|
|
400
|
+
EOF
|
|
401
|
+
|
|
391
402
|
# Actor B runs a LATER, plain (non-FlowDefinition) ensure-session on an unrelated subject on the
|
|
392
403
|
# SAME artifact root -- this overwrites the LEGACY global current.json (last-writer-wins, no
|
|
393
404
|
# active_flow_id/active_step_id at all) while leaving actor A's own per-actor current file
|
|
@@ -416,6 +427,7 @@ if flow_agents_node "workflow-sidecar" record-gate-claim "$AC11_GATE_ACTOR_A_DIR
|
|
|
416
427
|
--status pass \
|
|
417
428
|
--summary "Selected issue #291 for implementation." \
|
|
418
429
|
--expectation selected-work \
|
|
430
|
+
--evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$AC11_PULL_WORK_ARTIFACT\",\"summary\":\"Declared pull-work artifact naming bound Work Item $AC11_WORK_ITEM.\"}" \
|
|
419
431
|
--timestamp "2026-07-01T00:02:00Z" \
|
|
420
432
|
>"$TMPDIR_EVAL/ac11-gate-claim.out" 2>"$TMPDIR_EVAL/ac11-gate-claim.err"; then
|
|
421
433
|
pass "record-gate-claim (actor A) succeeds by resolving A's OWN per-actor current pointer, not B's stale legacy pointer (AC11)"
|