@kontourai/flow-agents 3.5.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/.github/workflows/ci.yml +4 -0
- package/CHANGELOG.md +15 -0
- package/build/src/builder-flow-run-adapter.d.ts +32 -3
- package/build/src/builder-flow-run-adapter.js +113 -20
- package/build/src/builder-flow-runtime.d.ts +26 -3
- package/build/src/builder-flow-runtime.js +502 -49
- package/build/src/builder-lifecycle-authority.d.ts +35 -0
- package/build/src/builder-lifecycle-authority.js +219 -0
- package/build/src/cli/assignment-provider.d.ts +14 -7
- package/build/src/cli/assignment-provider.js +128 -65
- package/build/src/cli/builder-run.js +46 -9
- package/build/src/cli/workflow-artifact-cleanup-audit.js +3 -0
- package/build/src/cli/workflow-sidecar.d.ts +30 -3
- package/build/src/cli/workflow-sidecar.js +825 -99
- package/build/src/cli/workflow.d.ts +2 -0
- package/build/src/cli/workflow.js +769 -0
- package/build/src/cli.js +2 -0
- package/build/src/flow-kit/validate.d.ts +17 -0
- package/build/src/flow-kit/validate.js +340 -2
- package/build/src/index.d.ts +4 -0
- package/build/src/index.js +7 -5
- package/build/src/lib/observed-command.d.ts +7 -0
- package/build/src/lib/observed-command.js +100 -0
- package/build/src/lib/package-version.d.ts +2 -0
- package/build/src/lib/package-version.js +13 -0
- package/build/src/lib/pinned-cli-command.d.ts +6 -0
- package/build/src/lib/pinned-cli-command.js +21 -0
- package/build/src/tools/generate-context-map.js +5 -3
- package/context/contracts/artifact-contract.md +1 -1
- package/context/scripts/hooks/config-protection.js +8 -1
- package/context/scripts/hooks/lib/config-protection-remedies.js +3 -0
- package/context/scripts/hooks/lib/kit-catalog.js +1 -1
- package/context/scripts/hooks/stop-goal-fit.js +79 -10
- package/docs/context-map.md +24 -20
- package/docs/developer-architecture.md +1 -1
- package/docs/public-workflow-cli.md +132 -0
- package/docs/skills-map.md +51 -27
- package/docs/spec/builder-flow-runtime.md +78 -40
- package/docs/workflow-usage-guide.md +110 -38
- package/evals/ci/run-baseline.sh +2 -0
- package/evals/fixtures/hook-influence/cases.json +2 -2
- package/evals/integration/test_builder_entry_enforcement.sh +57 -45
- package/evals/integration/test_builder_step_producers.sh +297 -6
- package/evals/integration/test_bundle_install.sh +258 -55
- 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 +573 -0
- 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/schemas/builder-lifecycle-authorization.schema.json +57 -0
- package/schemas/lifecycle-authority-keys.schema.json +25 -0
- package/schemas/workflow-state.schema.json +1 -1
- package/scripts/hooks/config-protection.js +8 -1
- package/scripts/hooks/lib/config-protection-remedies.js +3 -0
- package/scripts/hooks/lib/kit-catalog.js +1 -1
- package/scripts/hooks/stop-goal-fit.js +79 -10
- package/src/builder-flow-run-adapter.ts +156 -23
- package/src/builder-flow-runtime.ts +535 -53
- package/src/builder-lifecycle-authority.ts +218 -0
- package/src/cli/assignment-provider-lock.test.mjs +83 -0
- package/src/cli/assignment-provider.ts +91 -22
- package/src/cli/builder-flow-run-adapter.test.mjs +4 -2
- package/src/cli/builder-flow-runtime.test.mjs +597 -8
- package/src/cli/builder-run.ts +54 -9
- package/src/cli/kit-metadata-security.test.mjs +232 -6
- package/src/cli/public-api.test.mjs +15 -0
- package/src/cli/workflow-artifact-cleanup-audit.ts +3 -0
- package/src/cli/workflow-sidecar-execution-proof.test.mjs +90 -0
- package/src/cli/workflow-sidecar.ts +748 -99
- package/src/cli/workflow.ts +708 -0
- package/src/cli.ts +2 -0
- package/src/flow-kit/validate.ts +320 -2
- package/src/index.ts +20 -5
- package/src/lib/observed-command.ts +96 -0
- package/src/lib/package-version.ts +15 -0
- package/src/lib/pinned-cli-command.ts +23 -0
- package/src/tools/generate-context-map.ts +5 -3
|
@@ -59,8 +59,9 @@ if (fs.existsSync(actorRoot)) {
|
|
|
59
59
|
files.push(...fs.readdirSync(actorRoot).filter((name) => name.endsWith('.json')).map((name) => path.join(actorRoot, name)));
|
|
60
60
|
}
|
|
61
61
|
for (const file of files) {
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
const current = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
63
|
+
current.active_flow_id = 'builder.build';
|
|
64
|
+
current.active_step_id = 'design-probe';
|
|
64
65
|
fs.writeFileSync(file, `${JSON.stringify(current, null, 2)}\n`);
|
|
65
66
|
}
|
|
66
67
|
NODE
|
|
@@ -92,14 +93,16 @@ NODE
|
|
|
92
93
|
# ─── Helper: bootstrap a session for produce tests ───────────────────────────
|
|
93
94
|
setup_session_for_produce() {
|
|
94
95
|
local aroot="$1" slug="$2" step="$3"
|
|
95
|
-
mkdir -p "$aroot"
|
|
96
|
+
mkdir -p "$aroot/$slug"
|
|
97
|
+
printf '# Pull Work\n\nSelected Work Item: local:%s\n\nFixture probe decisions are reviewable here.\n' "$slug" > "$aroot/$slug/$slug--pull-work.md"
|
|
98
|
+
printf '{"schema_version":"1.0","task_slug":"%s","decision":"hold"}\n' "$slug" > "$aroot/$slug/release.json"
|
|
99
|
+
printf '{"schema_version":"1.0","task_slug":"%s","status":"learned","records":[]}\n' "$slug" > "$aroot/$slug/learning.json"
|
|
96
100
|
|
|
97
101
|
flow_agents_node "workflow-sidecar" ensure-session \
|
|
98
102
|
--artifact-root "$aroot" \
|
|
99
103
|
--task-slug "$slug" \
|
|
100
104
|
--title "Producer test: $step" \
|
|
101
105
|
--summary "Test gate-claim producer at $step." \
|
|
102
|
-
--flow-id builder.build \
|
|
103
106
|
--timestamp "2026-06-26T00:00:00Z" >/dev/null 2>&1
|
|
104
107
|
|
|
105
108
|
flow_agents_node "workflow-sidecar" init-plan "$aroot/$slug/$slug--deliver.md" \
|
|
@@ -115,13 +118,13 @@ setup_tamper_session() {
|
|
|
115
118
|
mkdir -p "$t_dir"
|
|
116
119
|
printf '# Repo\n' > "$t_dir/AGENTS.md"
|
|
117
120
|
mkdir -p "$t_dir/.kontourai/flow-agents/$slug"
|
|
121
|
+
printf '# Pull Work\n\nSelected Work Item: local:%s\n' "$slug" > "$t_dir/.kontourai/flow-agents/$slug/$slug--pull-work.md"
|
|
118
122
|
|
|
119
123
|
flow_agents_node "workflow-sidecar" ensure-session \
|
|
120
124
|
--artifact-root "$t_dir/.kontourai/flow-agents" \
|
|
121
125
|
--task-slug "$slug" \
|
|
122
126
|
--title "Tamper test: $step" \
|
|
123
127
|
--summary "Testing tamper detection." \
|
|
124
|
-
--flow-id builder.build \
|
|
125
128
|
--timestamp "2026-06-26T00:00:00Z" >/dev/null 2>&1
|
|
126
129
|
|
|
127
130
|
flow_agents_node "workflow-sidecar" init-plan "$t_dir/.kontourai/flow-agents/$slug/$slug--deliver.md" \
|
|
@@ -142,10 +145,19 @@ test_produce_claim() {
|
|
|
142
145
|
local aroot="$TMP/$slug/.kontourai/flow-agents"
|
|
143
146
|
setup_session_for_produce "$aroot" "$slug" "$step"
|
|
144
147
|
|
|
148
|
+
local artifact
|
|
149
|
+
case "$expectation" in
|
|
150
|
+
selected-work|pickup-probe-readiness|probe-decisions-or-accepted-gaps) artifact="$aroot/$slug/$slug--pull-work.md" ;;
|
|
151
|
+
pull-request-opened) artifact="$aroot/$slug/release.json" ;;
|
|
152
|
+
decision-evidence|learning-evidence) artifact="$aroot/$slug/learning.json" ;;
|
|
153
|
+
*) _fail "$label: fixture has no declared producer artifact"; return ;;
|
|
154
|
+
esac
|
|
155
|
+
|
|
145
156
|
if flow_agents_node "workflow-sidecar" record-gate-claim "$aroot/$slug" \
|
|
146
157
|
--status pass \
|
|
147
158
|
--summary "Test claim: $label" \
|
|
148
159
|
--expectation "$expectation" \
|
|
160
|
+
--evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$artifact\",\"summary\":\"Durable producer fixture artifact.\"}" \
|
|
149
161
|
--timestamp "2026-06-26T00:02:00Z" >/dev/null 2>&1; then
|
|
150
162
|
_pass "$label: record-gate-claim exits 0 at $step step"
|
|
151
163
|
else
|
|
@@ -169,6 +181,10 @@ test_produce_claim() {
|
|
|
169
181
|
console.error('expected status=verified, got', target.status);
|
|
170
182
|
process.exit(1);
|
|
171
183
|
}
|
|
184
|
+
if (typeof target.metadata?.expected_producer !== 'string' || typeof target.metadata?.recorded_by !== 'string') {
|
|
185
|
+
console.error('gate claim must distinguish its expected producer from the actor that recorded it');
|
|
186
|
+
process.exit(1);
|
|
187
|
+
}
|
|
172
188
|
" 2>/dev/null \
|
|
173
189
|
&& _pass "$label: bundle contains $expected_claim_type with subjectType=$expected_subject_type, status=verified" \
|
|
174
190
|
|| _fail "$label: bundle missing or incorrect $expected_claim_type claim"
|
|
@@ -387,10 +403,285 @@ test_tamper_blocks \
|
|
|
387
403
|
"builder.learn.evidence" \
|
|
388
404
|
"learn" "builder.learn.evidence" "release"
|
|
389
405
|
|
|
406
|
+
# ─── Public CLI happy path + route-back ─────────────────────────────────────
|
|
407
|
+
echo ""
|
|
408
|
+
echo "=== PUBLIC CLI: complete canonical skill/operation path ==="
|
|
409
|
+
flow_agents_build_ts || _fail "public CLI fixture build failed"
|
|
410
|
+
PUBLIC_ROOT="$TMP/public/.kontourai/flow-agents"
|
|
411
|
+
PUBLIC_SESSION="$PUBLIC_ROOT/acme-builder-901"
|
|
412
|
+
|
|
413
|
+
public_flow() {
|
|
414
|
+
CODEX_SESSION_ID=builder-public-producers node "$ROOT/build/src/cli.js" workflow "$@"
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
public_review() {
|
|
418
|
+
CODEX_SESSION_ID=builder-public-reviewer node "$ROOT/build/src/cli.js" workflow "$@"
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
assert_public_step() {
|
|
422
|
+
local step="$1" skills="$2" operations="$3" status="${4:-active}"
|
|
423
|
+
local report
|
|
424
|
+
report="$(public_flow status --session-dir "$PUBLIC_SESSION" --json 2>/dev/null)" || {
|
|
425
|
+
_fail "public status failed at $step"
|
|
426
|
+
return
|
|
427
|
+
}
|
|
428
|
+
if node - "$report" "$step" "$skills" "$operations" "$status" <<'NODE'
|
|
429
|
+
const [reportText, step, skills, operations, status] = process.argv.slice(2);
|
|
430
|
+
const report = JSON.parse(reportText);
|
|
431
|
+
const statusMatches = status === 'active-or-blocked' ? ['active', 'blocked'].includes(report.status) : report.status === status;
|
|
432
|
+
if (report.definition_id !== 'builder.build' || report.current_step !== step || !statusMatches) process.exit(1);
|
|
433
|
+
if ((report.next_action?.skills || []).join(',') !== skills) process.exit(2);
|
|
434
|
+
if ((report.next_action?.operations || []).join(',') !== operations) process.exit(3);
|
|
435
|
+
NODE
|
|
436
|
+
then
|
|
437
|
+
_pass "public run projects $step to ${skills:-no skill}${operations:+ / $operations}"
|
|
438
|
+
else
|
|
439
|
+
_fail "public run projection mismatch at $step: $report"
|
|
440
|
+
fi
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
record_public_expectation() {
|
|
444
|
+
local expectation="$1" status="${2:-pass}"
|
|
445
|
+
local artifact slug
|
|
446
|
+
slug="$(basename "$PUBLIC_SESSION")"
|
|
447
|
+
case "$expectation" in
|
|
448
|
+
shaped-problem|shaped-outcome|shaped-constraints|shaped-non-goals|shaped-success|shaped-risk|open-decisions|slices-defined|work-items-filed) artifact="$PUBLIC_SESSION/$slug--idea-to-backlog.md" ;;
|
|
449
|
+
pickup-probe-readiness|probe-decisions-or-accepted-gaps) artifact="$PUBLIC_SESSION/$slug--pull-work.md" ;;
|
|
450
|
+
implementation-plan) artifact="$PUBLIC_SESSION/$slug--plan-work.md" ;;
|
|
451
|
+
implementation-scope) artifact="$PUBLIC_SESSION/$slug--deliver.md" ;;
|
|
452
|
+
tests-evidence) artifact="$PUBLIC_SESSION/$slug--plan-work.md" ;;
|
|
453
|
+
merge-readiness) artifact="$PUBLIC_SESSION/$slug--evidence-gate.md" ;;
|
|
454
|
+
pull-request-opened|ci-merge-readiness) artifact="$PUBLIC_SESSION/release.json" ;;
|
|
455
|
+
decision-evidence|learning-evidence) artifact="$PUBLIC_SESSION/learning.json" ;;
|
|
456
|
+
*) _fail "public producer fixture has no durable artifact for $expectation"; return ;;
|
|
457
|
+
esac
|
|
458
|
+
local -a args=(evidence --session-dir "$PUBLIC_SESSION" --expectation "$expectation" --status "$status" --summary "public producer fixture records a reviewable durable artifact" --evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$artifact\",\"summary\":\"Fixture artifact for $expectation.\"}")
|
|
459
|
+
if [ "$expectation" = "tests-evidence" ] && [ "$status" = "pass" ]; then
|
|
460
|
+
local test_command criterion_one criterion_two command_ref
|
|
461
|
+
test_command="bash checks/check-public-session.sh .kontourai/flow-agents/$slug/state.json"
|
|
462
|
+
criterion_one="$(node - "$test_command" <<'NODE'
|
|
463
|
+
const command = process.argv[2];
|
|
464
|
+
process.stdout.write(JSON.stringify({ id: 'AC-1', status: 'pass', evidence_refs: [{ kind: 'command', excerpt: command, summary: 'Substantive fixture assertion for AC-1.' }] }));
|
|
465
|
+
NODE
|
|
466
|
+
)"
|
|
467
|
+
criterion_two="$(node - "$test_command" <<'NODE'
|
|
468
|
+
const command = process.argv[2];
|
|
469
|
+
process.stdout.write(JSON.stringify({ id: 'AC-2', status: 'pass', evidence_refs: [{ kind: 'command', excerpt: command, summary: 'Substantive fixture assertion for AC-2.' }] }));
|
|
470
|
+
NODE
|
|
471
|
+
)"
|
|
472
|
+
command_ref="$(node - "$test_command" <<'NODE'
|
|
473
|
+
const command = process.argv[2];
|
|
474
|
+
process.stdout.write(JSON.stringify({ kind: 'command', excerpt: command, summary: 'Exact project-local verification command.' }));
|
|
475
|
+
NODE
|
|
476
|
+
)"
|
|
477
|
+
args+=(--command "$test_command" --evidence-ref-json "$command_ref" --criterion-json "$criterion_one" --criterion-json "$criterion_two")
|
|
478
|
+
fi
|
|
479
|
+
local output
|
|
480
|
+
if ! output="$(public_flow "${args[@]}" 2>&1)"; then
|
|
481
|
+
_fail "public evidence failed for $expectation: $output"
|
|
482
|
+
fi
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
prepare_public_artifacts() {
|
|
486
|
+
node - "$PUBLIC_SESSION" <<'NODE'
|
|
487
|
+
const fs = require('node:fs');
|
|
488
|
+
const path = require('node:path');
|
|
489
|
+
const session = process.argv[2];
|
|
490
|
+
const slug = path.basename(session);
|
|
491
|
+
const write = (name, body) => fs.writeFileSync(path.join(session, name), body, 'utf8');
|
|
492
|
+
const projectRoot = path.dirname(path.dirname(path.dirname(session)));
|
|
493
|
+
const checksDir = path.join(projectRoot, 'checks');
|
|
494
|
+
fs.mkdirSync(checksDir, { recursive: true });
|
|
495
|
+
const checkScript = path.join(checksDir, 'check-public-session.sh');
|
|
496
|
+
fs.writeFileSync(checkScript, '#!/usr/bin/env bash\nset -eu\ntest -f "$1"\nprintf "1..1\\nok 1 - session exists\\n"\n', 'utf8');
|
|
497
|
+
fs.chmodSync(checkScript, 0o755);
|
|
498
|
+
write(`${slug}--idea-to-backlog.md`, '# Idea To Backlog Report\n\nShaped problem, slices, and filed work are reviewable here.\n');
|
|
499
|
+
write(`${slug}--pull-work.md`, '# Pull and Probe Report\n\nSelected work, scope, decisions, and accepted gaps are reviewable here.\n');
|
|
500
|
+
write(`${slug}--plan-work.md`, '# Plan\n\n## Definition Of Done\n\n- AC-1: The producer fixture records criterion-backed evidence.\n- AC-2: Every accepted criterion is backed by the exact test command.\n');
|
|
501
|
+
write(`${slug}--evidence-gate.md`, '# Evidence Gate\n\nAcceptance coverage and scope-integrity decision.\n');
|
|
502
|
+
write('acceptance.json', JSON.stringify({ schema_version: '1.0', task_slug: slug, criteria: [{ id: 'AC-1', description: 'The producer fixture records criterion-backed evidence.', status: 'pending', evidence_refs: [] }, { id: 'AC-2', description: 'Every accepted criterion is backed by the exact test command.', status: 'pending', evidence_refs: [] }], goal_fit: { status: 'pending', summary: 'Fixture has not completed Goal Fit review.' } }, null, 2));
|
|
503
|
+
write('handoff.json', JSON.stringify({ schema_version: '1.0', task_slug: slug, summary: 'Fixture execution handoff.', next_steps: ['Execute the reviewed plan.'], blockers: [] }, null, 2));
|
|
504
|
+
write('release.json', JSON.stringify({ schema_version: '1.0', task_slug: slug, decision: 'hold', updated_at: '2026-06-26T00:00:00Z', scope: 'producer fixture', evidence_ref: `${slug}--evidence-gate.md`, gates: [{ name: 'merge', status: 'hold', summary: 'Fixture is not authorized to merge.' }], 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));
|
|
505
|
+
write('learning.json', JSON.stringify({ schema_version: '1.0', task_slug: slug, status: 'learned', updated_at: '2026-06-26T00:00:00Z', records: [{ id: 'fixture-learning', recorded_at: '2026-06-26T00:00:00Z', source_refs: [`${slug}--evidence-gate.md`], outcome: 'success', facts: ['Fixture created reviewable durable artifacts.'], interpretation: 'No workflow correction is needed.', routing: [{ target: 'none', action: 'No follow-up required.', status: 'completed' }], correction: { needed: false, evidence: 'Fixture contract passes.' } }] }, null, 2));
|
|
506
|
+
NODE
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
mkdir -p "$PUBLIC_ROOT"
|
|
510
|
+
mkdir -p "$PUBLIC_SESSION"
|
|
511
|
+
printf 'Selected Work Item: acme/builder#901\n' > "$PUBLIC_SESSION/acme-builder-901--pull-work.md"
|
|
512
|
+
public_flow start --artifact-root "$PUBLIC_ROOT" --flow builder.build \
|
|
513
|
+
--work-item acme/builder#901 --assignment-provider local-file --summary "Public producer path" >/dev/null 2>&1 \
|
|
514
|
+
|| _fail "public workflow start failed"
|
|
515
|
+
prepare_public_artifacts
|
|
516
|
+
assert_public_step "design-probe" "pickup-probe" ""
|
|
517
|
+
record_public_expectation "pickup-probe-readiness"
|
|
518
|
+
assert_public_step "design-probe" "pickup-probe" "" "active-or-blocked"
|
|
519
|
+
record_public_expectation "probe-decisions-or-accepted-gaps"
|
|
520
|
+
assert_public_step "plan" "plan-work" ""
|
|
521
|
+
record_public_expectation "implementation-plan"
|
|
522
|
+
assert_public_step "execute" "execute-plan" ""
|
|
523
|
+
record_public_expectation "implementation-scope"
|
|
524
|
+
assert_public_step "verify" "review-work,verify-work" ""
|
|
525
|
+
if public_review critique --session-dir "$PUBLIC_SESSION" --verdict pass --summary "Missing lanes must fail." --artifact-ref "$PUBLIC_SESSION/$(basename "$PUBLIC_SESSION")--deliver.md" >/dev/null 2>&1; then
|
|
526
|
+
_fail "public critique accepted a passing review without lanes"
|
|
527
|
+
else
|
|
528
|
+
_pass "public critique rejects a passing review without lanes"
|
|
529
|
+
fi
|
|
530
|
+
PUBLIC_CRITIQUE_OUTPUT="$(public_review critique --session-dir "$PUBLIC_SESSION" \
|
|
531
|
+
--verdict pass \
|
|
532
|
+
--summary "Authenticated review found no blocking fixture findings." \
|
|
533
|
+
--artifact-ref "$PUBLIC_SESSION/$(basename "$PUBLIC_SESSION")--deliver.md" \
|
|
534
|
+
--lane-json "{\"id\":\"code-review\",\"status\":\"pass\",\"summary\":\"Public fixture code review completed.\",\"evidence_refs\":[{\"kind\":\"artifact\",\"file\":\"$PUBLIC_SESSION/$(basename "$PUBLIC_SESSION")--deliver.md\",\"summary\":\"Reviewed public fixture delivery artifact.\"}]}" 2>&1)" \
|
|
535
|
+
|| _fail "public authenticated critique failed before tests-evidence: $PUBLIC_CRITIQUE_OUTPUT"
|
|
536
|
+
PUBLIC_TEST_COMMAND="bash checks/check-public-session.sh .kontourai/flow-agents/$(basename "$PUBLIC_SESSION")/state.json"
|
|
537
|
+
if public_flow evidence --session-dir "$PUBLIC_SESSION" --expectation tests-evidence --status pass --command "bash -c true" --summary "Wrapped no-op must not count as tests evidence." \
|
|
538
|
+
--criterion-json '{"id":"AC-1","status":"pass","evidence_refs":[{"kind":"command","excerpt":"bash -c true","summary":"Wrapped no-op."}]}' \
|
|
539
|
+
--criterion-json '{"id":"AC-2","status":"pass","evidence_refs":[{"kind":"command","excerpt":"bash -c true","summary":"Wrapped no-op."}]}' >/dev/null 2>&1; then
|
|
540
|
+
_fail "public tests-evidence accepted a wrapped no-op command"
|
|
541
|
+
else
|
|
542
|
+
_pass "public tests-evidence rejects a wrapped no-op command"
|
|
543
|
+
fi
|
|
544
|
+
if public_flow evidence --session-dir "$PUBLIC_SESSION" --expectation tests-evidence --status pass --command "$PUBLIC_TEST_COMMAND" --summary "External-only criterion evidence must not pass." \
|
|
545
|
+
--criterion-json '{"id":"AC-1","status":"pass","evidence_refs":[{"kind":"external","url":"https://example.invalid/ac-1","summary":"External attestation only."}]}' \
|
|
546
|
+
--criterion-json '{"id":"AC-2","status":"pass","evidence_refs":[{"kind":"external","url":"https://example.invalid/ac-2","summary":"External attestation only."}]}' >/dev/null 2>&1; then
|
|
547
|
+
_fail "public tests-evidence accepted external-only passing criterion evidence"
|
|
548
|
+
else
|
|
549
|
+
_pass "public tests-evidence rejects external-only passing criterion evidence"
|
|
550
|
+
fi
|
|
551
|
+
if public_flow evidence --session-dir "$PUBLIC_SESSION" --expectation tests-evidence --status pass --command "$PUBLIC_TEST_COMMAND" --summary "Every criterion must cite the exact command." \
|
|
552
|
+
--criterion-json "{\"id\":\"AC-1\",\"status\":\"pass\",\"evidence_refs\":[{\"kind\":\"command\",\"excerpt\":\"$PUBLIC_TEST_COMMAND\",\"summary\":\"Exact command for AC-1.\"}]}" \
|
|
553
|
+
--criterion-json '{"id":"AC-2","status":"pass","evidence_refs":[{"kind":"command","excerpt":"bash checks/check-public-session.sh .kontourai/flow-agents/missing/state.json","summary":"Different command for AC-2."}]}' >/dev/null 2>&1; then
|
|
554
|
+
_fail "public tests-evidence accepted a criterion without the exact command"
|
|
555
|
+
else
|
|
556
|
+
_pass "public tests-evidence requires the exact command for every criterion"
|
|
557
|
+
fi
|
|
558
|
+
record_public_expectation "tests-evidence"
|
|
559
|
+
if node - "$PUBLIC_SESSION/trust.bundle" <<'NODE'
|
|
560
|
+
const fs = require('node:fs');
|
|
561
|
+
const bundle = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
|
|
562
|
+
const verified = (claimType, subjectType) => bundle.claims.some((claim) => (
|
|
563
|
+
claim.claimType === claimType
|
|
564
|
+
&& claim.subjectType === subjectType
|
|
565
|
+
&& claim.status === 'verified'
|
|
566
|
+
));
|
|
567
|
+
if (!verified('workflow.critique.review', 'workflow-critique')) process.exit(1);
|
|
568
|
+
if (!verified('workflow.acceptance.criterion', 'flow-step')) process.exit(2);
|
|
569
|
+
if (!verified('builder.verify.tests', 'flow-step')) process.exit(3);
|
|
570
|
+
NODE
|
|
571
|
+
then
|
|
572
|
+
_pass "public verify gate is backed by current critique, criterion, and test claims"
|
|
573
|
+
else
|
|
574
|
+
_fail "public verify gate is missing one or more declared trust-bundle claims"
|
|
575
|
+
fi
|
|
576
|
+
assert_public_step "merge-ready" "evidence-gate" ""
|
|
577
|
+
record_public_expectation "merge-readiness"
|
|
578
|
+
assert_public_step "pr-open" "" "publish-change"
|
|
579
|
+
record_public_expectation "pull-request-opened"
|
|
580
|
+
assert_public_step "merge-ready-ci" "release-readiness" ""
|
|
581
|
+
record_public_expectation "ci-merge-readiness"
|
|
582
|
+
assert_public_step "learn" "learning-review" ""
|
|
583
|
+
record_public_expectation "decision-evidence"
|
|
584
|
+
assert_public_step "learn" "learning-review" "" "active-or-blocked"
|
|
585
|
+
record_public_expectation "learning-evidence"
|
|
586
|
+
if node - "$PUBLIC_SESSION/trust.bundle" <<'NODE'
|
|
587
|
+
const fs = require('node:fs');
|
|
588
|
+
const bundle = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
|
|
589
|
+
if (!bundle.claims.some((claim) => claim.claimType === 'builder.learn.evidence' && claim.subjectType === 'release' && claim.status === 'verified')) process.exit(1);
|
|
590
|
+
NODE
|
|
591
|
+
then
|
|
592
|
+
_pass "learning-review records verified learning.json evidence"
|
|
593
|
+
else
|
|
594
|
+
_fail "learning-review did not record durable learning.json evidence in trust.bundle"
|
|
595
|
+
fi
|
|
596
|
+
assert_public_step "learn" "" "" "completed"
|
|
597
|
+
|
|
598
|
+
echo ""
|
|
599
|
+
echo "=== PUBLIC CLI: failed verify route-back remains canonical ==="
|
|
600
|
+
ROUTE_SESSION="$PUBLIC_ROOT/acme-builder-902"
|
|
601
|
+
PUBLIC_SESSION="$ROUTE_SESSION"
|
|
602
|
+
mkdir -p "$ROUTE_SESSION"
|
|
603
|
+
printf 'Selected Work Item: acme/builder#902\n' > "$ROUTE_SESSION/acme-builder-902--pull-work.md"
|
|
604
|
+
public_flow start --artifact-root "$PUBLIC_ROOT" --flow builder.build \
|
|
605
|
+
--work-item acme/builder#902 --assignment-provider local-file --summary "Public route-back path" >/dev/null 2>&1 \
|
|
606
|
+
|| _fail "route-back workflow start failed"
|
|
607
|
+
prepare_public_artifacts
|
|
608
|
+
for expectation in pickup-probe-readiness probe-decisions-or-accepted-gaps implementation-plan implementation-scope; do
|
|
609
|
+
record_public_expectation "$expectation"
|
|
610
|
+
done
|
|
611
|
+
ROUTE_CRITIQUE_OUTPUT="$(public_review critique --session-dir "$PUBLIC_SESSION" \
|
|
612
|
+
--verdict pass \
|
|
613
|
+
--summary "Authenticated review completed before failed verification evidence." \
|
|
614
|
+
--artifact-ref "$PUBLIC_SESSION/$(basename "$PUBLIC_SESSION")--deliver.md" \
|
|
615
|
+
--lane-json "{\"id\":\"code-review\",\"status\":\"pass\",\"summary\":\"Public fixture code review completed.\",\"evidence_refs\":[{\"kind\":\"artifact\",\"file\":\"$PUBLIC_SESSION/$(basename "$PUBLIC_SESSION")--deliver.md\",\"summary\":\"Reviewed public fixture delivery artifact.\"}]}" 2>&1)" \
|
|
616
|
+
|| _fail "public authenticated critique failed before failed tests-evidence: $ROUTE_CRITIQUE_OUTPUT"
|
|
617
|
+
record_public_expectation "tests-evidence" "fail"
|
|
618
|
+
ROUTE_REPORT="$(public_flow status --session-dir "$PUBLIC_SESSION" --json 2>/dev/null)"
|
|
619
|
+
if node - "$ROUTE_REPORT" <<'NODE'
|
|
620
|
+
const report = JSON.parse(process.argv[2]);
|
|
621
|
+
if (report.current_step !== 'verify') process.exit(1);
|
|
622
|
+
if ((report.next_action?.skills || []).join(',') !== 'review-work,verify-work') process.exit(2);
|
|
623
|
+
if (!/attempt 1\/3 returned to `verify`/.test(report.next_action?.summary || '')) process.exit(3);
|
|
624
|
+
NODE
|
|
625
|
+
then
|
|
626
|
+
_pass "failed verify evidence routes back through Flow with attempt 1/3 and canonical producers"
|
|
627
|
+
else
|
|
628
|
+
_fail "public failed-verify route-back was not projected correctly: $ROUTE_REPORT"
|
|
629
|
+
fi
|
|
630
|
+
|
|
631
|
+
echo ""
|
|
632
|
+
echo "=== PUBLIC CLI: complete builder.shape path when supported ==="
|
|
633
|
+
SHAPE_SESSION="$PUBLIC_ROOT/builder-shape-903"
|
|
634
|
+
PUBLIC_SESSION="$SHAPE_SESSION"
|
|
635
|
+
SHAPE_START_OUTPUT="$(public_flow start --artifact-root "$PUBLIC_ROOT" --flow builder.shape \
|
|
636
|
+
--task-slug builder-shape-903 --summary "Shape public producer path" 2>&1)"
|
|
637
|
+
if [ "$?" -ne 0 ]; then
|
|
638
|
+
if printf '%s' "$SHAPE_START_OUTPUT" | rg -q 'supports only|unsupported.*builder\.shape|Unknown workflow'; then
|
|
639
|
+
_pass "public builder.shape path is deferred until the installed runtime exposes it"
|
|
640
|
+
else
|
|
641
|
+
_fail "public builder.shape start failed unexpectedly: $SHAPE_START_OUTPUT"
|
|
642
|
+
fi
|
|
643
|
+
else
|
|
644
|
+
assert_public_shape_step() {
|
|
645
|
+
local step="$1" skills="$2" status="${3:-active}"
|
|
646
|
+
local report
|
|
647
|
+
report="$(public_flow status --session-dir "$SHAPE_SESSION" --json 2>/dev/null)" || {
|
|
648
|
+
_fail "public shape status failed at $step"
|
|
649
|
+
return
|
|
650
|
+
}
|
|
651
|
+
if node - "$report" "$step" "$skills" "$status" <<'NODE'
|
|
652
|
+
const [reportText, step, skills, status] = process.argv.slice(2);
|
|
653
|
+
const report = JSON.parse(reportText);
|
|
654
|
+
const statusMatches = status === 'active-or-completed'
|
|
655
|
+
? ['active', 'completed'].includes(report.status)
|
|
656
|
+
: status === 'active-or-blocked'
|
|
657
|
+
? ['active', 'blocked'].includes(report.status)
|
|
658
|
+
: report.status === status;
|
|
659
|
+
if (report.definition_id !== 'builder.shape' || report.current_step !== step || !statusMatches) process.exit(1);
|
|
660
|
+
if ((report.next_action?.skills || []).join(',') !== skills) process.exit(2);
|
|
661
|
+
NODE
|
|
662
|
+
then
|
|
663
|
+
_pass "public shape run projects $step to ${skills:-no skill}"
|
|
664
|
+
else
|
|
665
|
+
_fail "public shape projection mismatch at $step: $report"
|
|
666
|
+
fi
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
prepare_public_artifacts
|
|
670
|
+
assert_public_shape_step "shape" "idea-to-backlog" "active-or-blocked"
|
|
671
|
+
for expectation in shaped-problem shaped-outcome shaped-constraints shaped-non-goals shaped-success shaped-risk; do
|
|
672
|
+
record_public_expectation "$expectation"
|
|
673
|
+
done
|
|
674
|
+
assert_public_shape_step "breakdown" "idea-to-backlog"
|
|
675
|
+
record_public_expectation "slices-defined"
|
|
676
|
+
assert_public_shape_step "file-issues" "idea-to-backlog"
|
|
677
|
+
record_public_expectation "work-items-filed"
|
|
678
|
+
assert_public_shape_step "shape-done" "" "active-or-completed"
|
|
679
|
+
fi
|
|
680
|
+
|
|
390
681
|
# ─── Summary ──────────────────────────────────────────────────────────────────
|
|
391
682
|
echo ""
|
|
392
683
|
if [ "$errors" -eq 0 ]; then
|
|
393
|
-
echo "Builder step producer tests passed (
|
|
684
|
+
echo "Builder step producer tests passed (legacy tamper checks plus full public happy path and route-back)."
|
|
394
685
|
exit 0
|
|
395
686
|
fi
|
|
396
687
|
echo "Builder step producer tests FAILED: $errors issue(s)."
|