@kontourai/flow-agents 3.6.0 → 3.8.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 +19 -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 +407 -51
- package/build/src/cli/assignment-provider.d.ts +4 -7
- package/build/src/cli/assignment-provider.js +80 -14
- 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 +825 -103
- package/build/src/cli/workflow.js +301 -43
- 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/build-universal-bundles.js +53 -3
- 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/getting-started.md +9 -1
- package/docs/public-workflow-cli.md +76 -7
- package/docs/skills-map.md +51 -27
- package/docs/spec/builder-flow-runtime.md +75 -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 +330 -6
- package/evals/integration/test_bundle_install.sh +318 -65
- package/evals/integration/test_bundle_lifecycle.sh +4 -6
- 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_install_merge.sh +18 -8
- 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 +334 -14
- 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_universal_bundles.sh +44 -1
- 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/packaging/README.md +1 -1
- package/scripts/README.md +1 -1
- package/scripts/hooks/lib/kit-catalog.js +1 -1
- package/scripts/hooks/stop-goal-fit.js +78 -9
- package/scripts/install-codex-home.sh +63 -23
- package/scripts/install-owned-files.js +18 -2
- package/src/builder-flow-run-adapter.ts +118 -32
- package/src/builder-flow-runtime.ts +426 -64
- package/src/cli/assignment-provider-lock.test.mjs +83 -0
- package/src/cli/assignment-provider.ts +75 -14
- package/src/cli/builder-flow-run-adapter.test.mjs +4 -2
- package/src/cli/builder-flow-runtime.test.mjs +436 -18
- 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 +746 -103
- package/src/cli/workflow.ts +288 -41
- 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/build-universal-bundles.ts +51 -3
- package/src/tools/generate-context-map.ts +5 -3
|
@@ -13,6 +13,12 @@ trap 'rm -rf "$TMP"' EXIT
|
|
|
13
13
|
pass() { printf ' PASS %s\n' "$1"; }
|
|
14
14
|
fail() { printf ' FAIL %s\n' "$1"; errors=$((errors + 1)); }
|
|
15
15
|
|
|
16
|
+
seed_pull_work_report() {
|
|
17
|
+
local artifact_root="$1" slug="$2" work_item_ref="$3"
|
|
18
|
+
mkdir -p "$artifact_root/$slug"
|
|
19
|
+
printf '# Pull Work\n\nSelected Work Item: %s\n' "$work_item_ref" > "$artifact_root/$slug/$slug--pull-work.md"
|
|
20
|
+
}
|
|
21
|
+
|
|
16
22
|
WRITER="workflow-sidecar"
|
|
17
23
|
|
|
18
24
|
echo "=== Builder workflow entry enforcement ==="
|
|
@@ -185,14 +191,20 @@ else
|
|
|
185
191
|
fi
|
|
186
192
|
|
|
187
193
|
LOCAL_ROOT="$TMP/local/.kontourai/flow-agents"
|
|
188
|
-
|
|
194
|
+
seed_pull_work_report "$LOCAL_ROOT" "local-request" "local:local-request"
|
|
195
|
+
cat >"$LOCAL_ROOT/local-request/work-item.json" <<'JSON'
|
|
196
|
+
{"id":"local-request","title":"Local request","source_provider":{"kind":"local","path":"work-item.json"}}
|
|
197
|
+
JSON
|
|
198
|
+
cat >"$LOCAL_ROOT/local-request/state.json" <<'JSON'
|
|
199
|
+
{"schema_version":"1.0","task_slug":"local-request","status":"planned","phase":"pickup","work_item_refs":["local:local-request"],"next_action":{"status":"continue","summary":"Start Builder."}}
|
|
200
|
+
JSON
|
|
201
|
+
if FLOW_AGENTS_ACTOR=builder-entry-local node "$ROOT/build/src/cli.js" workflow start \
|
|
189
202
|
--artifact-root "$LOCAL_ROOT" \
|
|
203
|
+
--flow builder.build \
|
|
204
|
+
--work-item local:local-request \
|
|
190
205
|
--task-slug local-request \
|
|
191
|
-
--actor builder-entry-local \
|
|
192
206
|
--title "Local request" \
|
|
193
|
-
--summary "Providerless work still needs an anchor."
|
|
194
|
-
--flow-id builder.build \
|
|
195
|
-
--timestamp "2026-07-10T00:00:00Z" >"$TMP/local.out" 2>&1; then
|
|
207
|
+
--summary "Providerless work still needs an anchor." >"$TMP/local.out" 2>&1; then
|
|
196
208
|
if node - "$LOCAL_ROOT" <<'NODE'
|
|
197
209
|
const fs = require('node:fs');
|
|
198
210
|
const path = require('node:path');
|
|
@@ -228,14 +240,13 @@ fi
|
|
|
228
240
|
|
|
229
241
|
LOCAL_SESSION="$LOCAL_ROOT/local-request"
|
|
230
242
|
FLOW_DIGEST_BEFORE="$(find "$TMP/local/.kontourai/flow/runs/local-request" -type f -print0 | sort -z | xargs -0 shasum -a 256)"
|
|
231
|
-
if
|
|
243
|
+
if FLOW_AGENTS_ACTOR=builder-entry-local node "$ROOT/build/src/cli.js" workflow start \
|
|
232
244
|
--artifact-root "$LOCAL_ROOT" \
|
|
245
|
+
--flow builder.build \
|
|
246
|
+
--work-item local:local-request \
|
|
233
247
|
--task-slug local-request \
|
|
234
|
-
--actor builder-entry-local \
|
|
235
248
|
--title "Local request" \
|
|
236
|
-
--summary "Providerless work still needs an anchor." \
|
|
237
|
-
--flow-id builder.build \
|
|
238
|
-
--timestamp "2026-07-10T00:00:00Z" >"$TMP/builder-ensure-again.out" 2>&1 \
|
|
249
|
+
--summary "Providerless work still needs an anchor." >"$TMP/builder-ensure-again.out" 2>&1 \
|
|
239
250
|
&& [[ "$FLOW_DIGEST_BEFORE" == "$(find "$TMP/local/.kontourai/flow/runs/local-request" -type f -print0 | sort -z | xargs -0 shasum -a 256)" ]] \
|
|
240
251
|
&& node - "$TMP/local" "$LOCAL_SESSION" <<'NODE'
|
|
241
252
|
const fs = require('node:fs');
|
|
@@ -258,6 +269,7 @@ fi
|
|
|
258
269
|
BROKEN_PROJECT="$TMP/broken-start"
|
|
259
270
|
BROKEN_ROOT="$BROKEN_PROJECT/.kontourai/flow-agents"
|
|
260
271
|
mkdir -p "$BROKEN_PROJECT/.kontourai"
|
|
272
|
+
seed_pull_work_report "$BROKEN_ROOT" "broken-start" "local:broken-start"
|
|
261
273
|
printf 'not a run-store directory\n' > "$BROKEN_PROJECT/.kontourai/flow"
|
|
262
274
|
if flow_agents_node "$WRITER" ensure-session \
|
|
263
275
|
--artifact-root "$BROKEN_ROOT" \
|
|
@@ -265,12 +277,9 @@ if flow_agents_node "$WRITER" ensure-session \
|
|
|
265
277
|
--actor builder-entry-broken \
|
|
266
278
|
--title "Broken start" \
|
|
267
279
|
--summary "Flow startup must fail visibly." \
|
|
268
|
-
--flow-id builder.build >"$TMP/broken-start.out" 2>&1
|
|
269
|
-
|
|
270
|
-
elif [[ -f "$BROKEN_ROOT/broken-start/state.json" ]] \
|
|
280
|
+
--flow-id builder.build >"$TMP/broken-start.out" 2>&1 \
|
|
281
|
+
&& [[ -f "$BROKEN_ROOT/broken-start/state.json" ]] \
|
|
271
282
|
&& [[ ! -e "$BROKEN_PROJECT/.kontourai/flow/runs/broken-start" ]] \
|
|
272
|
-
&& grep -q 'canonical Builder Flow entry failed' "$TMP/broken-start.out" \
|
|
273
|
-
&& grep -q 'Re-run the same ensure-session command' "$TMP/broken-start.out" \
|
|
274
283
|
&& node - "$BROKEN_ROOT/broken-start/state.json" <<'NODE'
|
|
275
284
|
const fs = require('node:fs');
|
|
276
285
|
const state = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
|
|
@@ -278,19 +287,19 @@ if (state.flow_run) process.exit(1);
|
|
|
278
287
|
if (!state.next_action?.command?.includes("'workflow' 'start'")) process.exit(1);
|
|
279
288
|
NODE
|
|
280
289
|
then
|
|
281
|
-
pass "
|
|
290
|
+
pass "private writer leaves public retry guidance without touching an invalid Flow store"
|
|
282
291
|
else
|
|
283
|
-
fail "
|
|
292
|
+
fail "private writer touched canonical Flow or lost public retry guidance: $(cat "$TMP/broken-start.out")"
|
|
284
293
|
fi
|
|
285
294
|
|
|
286
295
|
rm -f "$BROKEN_PROJECT/.kontourai/flow"
|
|
287
|
-
if
|
|
296
|
+
if FLOW_AGENTS_ACTOR=builder-entry-broken node "$ROOT/build/src/cli.js" workflow start \
|
|
288
297
|
--artifact-root "$BROKEN_ROOT" \
|
|
298
|
+
--flow builder.build \
|
|
299
|
+
--work-item local:broken-start \
|
|
289
300
|
--task-slug broken-start \
|
|
290
|
-
--actor builder-entry-broken \
|
|
291
301
|
--title "Broken start" \
|
|
292
|
-
--summary "Flow startup must recover from persisted acquisition provenance." \
|
|
293
|
-
--flow-id builder.build >"$TMP/broken-start-retry.out" 2>&1 \
|
|
302
|
+
--summary "Flow startup must recover from persisted acquisition provenance." >"$TMP/broken-start-retry.out" 2>&1 \
|
|
294
303
|
&& node - "$BROKEN_PROJECT" <<'NODE'
|
|
295
304
|
const fs = require('node:fs');
|
|
296
305
|
const path = require('node:path');
|
|
@@ -301,7 +310,7 @@ if (flowState.current_step !== 'design-probe') process.exit(1);
|
|
|
301
310
|
if (!(bundle.claims || []).some((claim) => claim.claimType === 'builder.pull-work.selected' && claim.status === 'verified')) process.exit(1);
|
|
302
311
|
NODE
|
|
303
312
|
then
|
|
304
|
-
pass "
|
|
313
|
+
pass "public startup consumes exact persisted acquisition provenance and advances canonical Flow"
|
|
305
314
|
else
|
|
306
315
|
fail "interrupted acquisition could not recover: $(cat "$TMP/broken-start-retry.out")"
|
|
307
316
|
fi
|
|
@@ -337,15 +346,14 @@ const fs = require('node:fs');
|
|
|
337
346
|
const path = require('node:path');
|
|
338
347
|
const project = process.argv[2];
|
|
339
348
|
const session = path.join(project, '.kontourai', 'flow-agents', 'skipped-ownership');
|
|
340
|
-
const flowState = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow', 'runs', 'skipped-ownership', 'state.json'), 'utf8'));
|
|
341
349
|
const sidecar = JSON.parse(fs.readFileSync(path.join(session, 'state.json'), 'utf8'));
|
|
342
|
-
if (
|
|
343
|
-
if (
|
|
350
|
+
if (sidecar.flow_run) process.exit(1);
|
|
351
|
+
if (fs.existsSync(path.join(project, '.kontourai', 'flow', 'runs', 'skipped-ownership'))) process.exit(1);
|
|
344
352
|
if (fs.existsSync(path.join(session, 'trust.bundle'))) process.exit(1);
|
|
345
353
|
if (fs.existsSync(path.join(project, '.kontourai', 'flow-agents', 'assignment', 'skipped-ownership.json'))) process.exit(1);
|
|
346
354
|
NODE
|
|
347
355
|
then
|
|
348
|
-
pass "skipped
|
|
356
|
+
pass "private skipped-ownership seed creates no assignment, evidence, or canonical Flow"
|
|
349
357
|
else
|
|
350
358
|
fail "unproven ownership advanced the canonical run: $(cat "$TMP/skipped.out")"
|
|
351
359
|
fi
|
|
@@ -364,15 +372,14 @@ const fs = require('node:fs');
|
|
|
364
372
|
const path = require('node:path');
|
|
365
373
|
const project = process.argv[2];
|
|
366
374
|
const session = path.join(project, '.kontourai', 'flow-agents', 'arbitrary-session-name');
|
|
367
|
-
const flowState = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow', 'runs', 'arbitrary-session-name', 'state.json'), 'utf8'));
|
|
368
375
|
const sidecar = JSON.parse(fs.readFileSync(path.join(session, 'state.json'), 'utf8'));
|
|
369
|
-
if (
|
|
370
|
-
if (sidecar.flow_run
|
|
376
|
+
if (JSON.stringify(sidecar.work_item_refs) !== JSON.stringify(['kontourai/flow-agents#541'])) process.exit(1);
|
|
377
|
+
if (sidecar.flow_run || fs.existsSync(path.join(project, '.kontourai', 'flow', 'runs', 'arbitrary-session-name'))) process.exit(1);
|
|
371
378
|
if (fs.existsSync(path.join(session, 'trust.bundle'))) process.exit(1);
|
|
372
379
|
if (!fs.existsSync(path.join(project, '.kontourai', 'flow-agents', 'assignment', 'arbitrary-session-name.json'))) process.exit(1);
|
|
373
380
|
NODE
|
|
374
381
|
then
|
|
375
|
-
pass "
|
|
382
|
+
pass "private mismatched-subject seed records scope but cannot create or advance canonical Flow"
|
|
376
383
|
else
|
|
377
384
|
fail "mismatched assignment subject was treated as exact Work Item evidence: $(cat "$TMP/mismatched-subject.out")"
|
|
378
385
|
fi
|
|
@@ -462,8 +469,7 @@ const fs = require('node:fs');
|
|
|
462
469
|
const path = require('node:path');
|
|
463
470
|
const project = process.argv[2];
|
|
464
471
|
const session = path.join(project, '.kontourai', 'flow-agents', 'preexisting-selection');
|
|
465
|
-
|
|
466
|
-
if (flowState.current_step !== 'pull-work') process.exit(1);
|
|
472
|
+
if (fs.existsSync(path.join(project, '.kontourai', 'flow', 'runs', 'preexisting-selection'))) process.exit(1);
|
|
467
473
|
if (fs.existsSync(path.join(session, 'trust.bundle'))) process.exit(1);
|
|
468
474
|
NODE
|
|
469
475
|
then
|
|
@@ -497,31 +503,35 @@ NODE
|
|
|
497
503
|
fi
|
|
498
504
|
fi
|
|
499
505
|
|
|
500
|
-
|
|
506
|
+
printf '# Plan Work\n\nRoute-back fixture plan evidence.\n' > "$LOCAL_SESSION/local-request--plan-work.md"
|
|
507
|
+
printf '# Delivery\n\nRoute-back fixture execution evidence.\n' > "$LOCAL_SESSION/local-request--deliver.md"
|
|
508
|
+
|
|
509
|
+
if FLOW_AGENTS_ACTOR=builder-entry-local node "$ROOT/build/src/cli.js" workflow evidence --session-dir "$LOCAL_SESSION" \
|
|
501
510
|
--expectation pickup-probe-readiness \
|
|
502
511
|
--status pass \
|
|
503
512
|
--summary "Pickup Probe confirmed scope and planning readiness." \
|
|
504
|
-
--evidence-ref-json '{"kind":"artifact","file":".kontourai/flow-agents/local-request/work
|
|
505
|
-
&&
|
|
513
|
+
--evidence-ref-json '{"kind":"artifact","file":".kontourai/flow-agents/local-request/local-request--pull-work.md","summary":"Declared pull-work fixture evidence."}' >/dev/null 2>&1 \
|
|
514
|
+
&& FLOW_AGENTS_ACTOR=builder-entry-local node "$ROOT/build/src/cli.js" workflow evidence --session-dir "$LOCAL_SESSION" \
|
|
506
515
|
--expectation probe-decisions-or-accepted-gaps \
|
|
507
516
|
--status pass \
|
|
508
517
|
--summary "Probe decisions and accepted gaps are recorded." \
|
|
509
|
-
--evidence-ref-json '{"kind":"artifact","file":".kontourai/flow-agents/local-request/work
|
|
510
|
-
&&
|
|
518
|
+
--evidence-ref-json '{"kind":"artifact","file":".kontourai/flow-agents/local-request/local-request--pull-work.md","summary":"Declared pull-work decision fixture evidence."}' >/dev/null 2>&1 \
|
|
519
|
+
&& FLOW_AGENTS_ACTOR=builder-entry-local node "$ROOT/build/src/cli.js" workflow evidence --session-dir "$LOCAL_SESSION" \
|
|
511
520
|
--expectation implementation-plan \
|
|
512
521
|
--status pass \
|
|
513
522
|
--summary "Implementation plan records files, sequence, and evidence." \
|
|
514
|
-
--evidence-ref-json '{"kind":"artifact","file":".kontourai/flow-agents/local-request/work
|
|
515
|
-
&&
|
|
523
|
+
--evidence-ref-json '{"kind":"artifact","file":".kontourai/flow-agents/local-request/local-request--plan-work.md","summary":"Declared plan fixture evidence."}' >/dev/null 2>&1 \
|
|
524
|
+
&& FLOW_AGENTS_ACTOR=builder-entry-local node "$ROOT/build/src/cli.js" workflow evidence --session-dir "$LOCAL_SESSION" \
|
|
516
525
|
--expectation implementation-scope \
|
|
517
526
|
--status pass \
|
|
518
527
|
--summary "Implementation scope and changed files are recorded." \
|
|
519
|
-
--evidence-ref-json '{"kind":"artifact","file":".kontourai/flow-agents/local-request/
|
|
520
|
-
&&
|
|
528
|
+
--evidence-ref-json '{"kind":"artifact","file":".kontourai/flow-agents/local-request/local-request--deliver.md","summary":"Declared execution fixture evidence."}' >/dev/null 2>&1 \
|
|
529
|
+
&& FLOW_AGENTS_ACTOR=builder-entry-local node "$ROOT/build/src/cli.js" workflow evidence --session-dir "$LOCAL_SESSION" \
|
|
521
530
|
--expectation tests-evidence \
|
|
522
531
|
--status fail \
|
|
523
532
|
--route-reason implementation_defect \
|
|
524
533
|
--summary "Verification found an implementation defect." \
|
|
534
|
+
--command false \
|
|
525
535
|
--evidence-ref-json '{"kind":"artifact","file":".kontourai/flow-agents/local-request/work-item.json","summary":"Failed verification fixture evidence."}' >"$TMP/route-back.out" 2>&1 \
|
|
526
536
|
&& node - "$TMP/local" "$LOCAL_SESSION" <<'NODE'
|
|
527
537
|
const fs = require('node:fs');
|
|
@@ -542,6 +552,7 @@ else
|
|
|
542
552
|
fi
|
|
543
553
|
|
|
544
554
|
PROVIDER_ROOT="$TMP/provider/.kontourai/flow-agents"
|
|
555
|
+
seed_pull_work_report "$PROVIDER_ROOT" "kontourai-flow-agents-438" "kontourai/flow-agents#438"
|
|
545
556
|
if flow_agents_node "$WRITER" ensure-session \
|
|
546
557
|
--artifact-root "$PROVIDER_ROOT" \
|
|
547
558
|
--work-item "kontourai/flow-agents#438" \
|
|
@@ -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,318 @@ 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" = "fail" ]; then
|
|
460
|
+
args+=(--route-reason implementation_defect)
|
|
461
|
+
fi
|
|
462
|
+
if [ "$expectation" = "tests-evidence" ] && [ "$status" = "pass" ]; then
|
|
463
|
+
local test_command criterion_one criterion_two command_ref
|
|
464
|
+
test_command="bash checks/check-public-session.sh .kontourai/flow-agents/$slug/state.json"
|
|
465
|
+
criterion_one="$(node - "$test_command" <<'NODE'
|
|
466
|
+
const command = process.argv[2];
|
|
467
|
+
process.stdout.write(JSON.stringify({ id: 'AC-1', status: 'pass', evidence_refs: [{ kind: 'command', excerpt: command, summary: 'Substantive fixture assertion for AC-1.' }] }));
|
|
468
|
+
NODE
|
|
469
|
+
)"
|
|
470
|
+
criterion_two="$(node - "$test_command" <<'NODE'
|
|
471
|
+
const command = process.argv[2];
|
|
472
|
+
process.stdout.write(JSON.stringify({ id: 'AC-2', status: 'pass', evidence_refs: [{ kind: 'command', excerpt: command, summary: 'Substantive fixture assertion for AC-2.' }] }));
|
|
473
|
+
NODE
|
|
474
|
+
)"
|
|
475
|
+
command_ref="$(node - "$test_command" <<'NODE'
|
|
476
|
+
const command = process.argv[2];
|
|
477
|
+
process.stdout.write(JSON.stringify({ kind: 'command', excerpt: command, summary: 'Exact project-local verification command.' }));
|
|
478
|
+
NODE
|
|
479
|
+
)"
|
|
480
|
+
args+=(--command "$test_command" --evidence-ref-json "$command_ref" --criterion-json "$criterion_one" --criterion-json "$criterion_two")
|
|
481
|
+
fi
|
|
482
|
+
local output
|
|
483
|
+
if ! output="$(public_flow "${args[@]}" 2>&1)"; then
|
|
484
|
+
_fail "public evidence failed for $expectation: $output"
|
|
485
|
+
fi
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
prepare_public_artifacts() {
|
|
489
|
+
node - "$PUBLIC_SESSION" <<'NODE'
|
|
490
|
+
const fs = require('node:fs');
|
|
491
|
+
const path = require('node:path');
|
|
492
|
+
const session = process.argv[2];
|
|
493
|
+
const slug = path.basename(session);
|
|
494
|
+
const write = (name, body) => fs.writeFileSync(path.join(session, name), body, 'utf8');
|
|
495
|
+
const projectRoot = path.dirname(path.dirname(path.dirname(session)));
|
|
496
|
+
const checksDir = path.join(projectRoot, 'checks');
|
|
497
|
+
fs.mkdirSync(checksDir, { recursive: true });
|
|
498
|
+
const checkScript = path.join(checksDir, 'check-public-session.sh');
|
|
499
|
+
fs.writeFileSync(checkScript, '#!/usr/bin/env bash\nset -eu\ntest -f "$1"\nprintf "1..1\\nok 1 - session exists\\n"\n', 'utf8');
|
|
500
|
+
fs.chmodSync(checkScript, 0o755);
|
|
501
|
+
write(`${slug}--idea-to-backlog.md`, '# Idea To Backlog Report\n\nShaped problem, slices, and filed work are reviewable here.\n');
|
|
502
|
+
write(`${slug}--pull-work.md`, '# Pull and Probe Report\n\nSelected work, scope, decisions, and accepted gaps are reviewable here.\n');
|
|
503
|
+
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');
|
|
504
|
+
write(`${slug}--evidence-gate.md`, '# Evidence Gate\n\nAcceptance coverage and scope-integrity decision.\n');
|
|
505
|
+
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));
|
|
506
|
+
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));
|
|
507
|
+
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));
|
|
508
|
+
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));
|
|
509
|
+
NODE
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
mkdir -p "$PUBLIC_ROOT"
|
|
513
|
+
mkdir -p "$PUBLIC_SESSION"
|
|
514
|
+
printf 'Selected Work Item: acme/builder#901\n' > "$PUBLIC_SESSION/acme-builder-901--pull-work.md"
|
|
515
|
+
public_flow start --artifact-root "$PUBLIC_ROOT" --flow builder.build \
|
|
516
|
+
--work-item acme/builder#901 --assignment-provider local-file --summary "Public producer path" >/dev/null 2>&1 \
|
|
517
|
+
|| _fail "public workflow start failed"
|
|
518
|
+
prepare_public_artifacts
|
|
519
|
+
assert_public_step "design-probe" "pickup-probe" ""
|
|
520
|
+
record_public_expectation "pickup-probe-readiness"
|
|
521
|
+
assert_public_step "design-probe" "pickup-probe" "" "active-or-blocked"
|
|
522
|
+
record_public_expectation "probe-decisions-or-accepted-gaps"
|
|
523
|
+
assert_public_step "plan" "plan-work" ""
|
|
524
|
+
record_public_expectation "implementation-plan"
|
|
525
|
+
assert_public_step "execute" "execute-plan" ""
|
|
526
|
+
record_public_expectation "implementation-scope"
|
|
527
|
+
assert_public_step "verify" "review-work,verify-work" ""
|
|
528
|
+
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
|
|
529
|
+
_fail "public critique accepted a passing review without lanes"
|
|
530
|
+
else
|
|
531
|
+
_pass "public critique rejects a passing review without lanes"
|
|
532
|
+
fi
|
|
533
|
+
PUBLIC_CRITIQUE_OUTPUT="$(public_review critique --session-dir "$PUBLIC_SESSION" \
|
|
534
|
+
--verdict pass \
|
|
535
|
+
--summary "Authenticated review found no blocking fixture findings." \
|
|
536
|
+
--artifact-ref "$PUBLIC_SESSION/$(basename "$PUBLIC_SESSION")--deliver.md" \
|
|
537
|
+
--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)" \
|
|
538
|
+
|| _fail "public authenticated critique failed before tests-evidence: $PUBLIC_CRITIQUE_OUTPUT"
|
|
539
|
+
PUBLIC_TEST_COMMAND="bash checks/check-public-session.sh .kontourai/flow-agents/$(basename "$PUBLIC_SESSION")/state.json"
|
|
540
|
+
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." \
|
|
541
|
+
--criterion-json '{"id":"AC-1","status":"pass","evidence_refs":[{"kind":"command","excerpt":"bash -c true","summary":"Wrapped no-op."}]}' \
|
|
542
|
+
--criterion-json '{"id":"AC-2","status":"pass","evidence_refs":[{"kind":"command","excerpt":"bash -c true","summary":"Wrapped no-op."}]}' >/dev/null 2>&1; then
|
|
543
|
+
_fail "public tests-evidence accepted a wrapped no-op command"
|
|
544
|
+
else
|
|
545
|
+
_pass "public tests-evidence rejects a wrapped no-op command"
|
|
546
|
+
fi
|
|
547
|
+
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." \
|
|
548
|
+
--criterion-json '{"id":"AC-1","status":"pass","evidence_refs":[{"kind":"external","url":"https://example.invalid/ac-1","summary":"External attestation only."}]}' \
|
|
549
|
+
--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
|
|
550
|
+
_fail "public tests-evidence accepted external-only passing criterion evidence"
|
|
551
|
+
else
|
|
552
|
+
_pass "public tests-evidence rejects external-only passing criterion evidence"
|
|
553
|
+
fi
|
|
554
|
+
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." \
|
|
555
|
+
--criterion-json "{\"id\":\"AC-1\",\"status\":\"pass\",\"evidence_refs\":[{\"kind\":\"command\",\"excerpt\":\"$PUBLIC_TEST_COMMAND\",\"summary\":\"Exact command for AC-1.\"}]}" \
|
|
556
|
+
--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
|
|
557
|
+
_fail "public tests-evidence accepted a criterion without the exact command"
|
|
558
|
+
else
|
|
559
|
+
_pass "public tests-evidence requires the exact command for every criterion"
|
|
560
|
+
fi
|
|
561
|
+
record_public_expectation "tests-evidence"
|
|
562
|
+
if node - "$PUBLIC_SESSION/trust.bundle" <<'NODE'
|
|
563
|
+
const fs = require('node:fs');
|
|
564
|
+
const bundle = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
|
|
565
|
+
const verified = (claimType, subjectType) => bundle.claims.some((claim) => (
|
|
566
|
+
claim.claimType === claimType
|
|
567
|
+
&& claim.subjectType === subjectType
|
|
568
|
+
&& claim.status === 'verified'
|
|
569
|
+
));
|
|
570
|
+
if (!verified('workflow.critique.review', 'workflow-critique')) process.exit(1);
|
|
571
|
+
if (!verified('workflow.acceptance.criterion', 'flow-step')) process.exit(2);
|
|
572
|
+
if (!verified('builder.verify.tests', 'flow-step')) process.exit(3);
|
|
573
|
+
NODE
|
|
574
|
+
then
|
|
575
|
+
_pass "public verify gate is backed by current critique, criterion, and test claims"
|
|
576
|
+
else
|
|
577
|
+
_fail "public verify gate is missing one or more declared trust-bundle claims"
|
|
578
|
+
fi
|
|
579
|
+
assert_public_step "merge-ready" "evidence-gate" ""
|
|
580
|
+
record_public_expectation "merge-readiness"
|
|
581
|
+
assert_public_step "pr-open" "" "publish-change"
|
|
582
|
+
record_public_expectation "pull-request-opened"
|
|
583
|
+
assert_public_step "merge-ready-ci" "release-readiness" ""
|
|
584
|
+
record_public_expectation "ci-merge-readiness"
|
|
585
|
+
assert_public_step "learn" "learning-review" ""
|
|
586
|
+
record_public_expectation "decision-evidence"
|
|
587
|
+
assert_public_step "learn" "learning-review" "" "active-or-blocked"
|
|
588
|
+
record_public_expectation "learning-evidence"
|
|
589
|
+
if node - "$PUBLIC_SESSION/trust.bundle" <<'NODE'
|
|
590
|
+
const fs = require('node:fs');
|
|
591
|
+
const bundle = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
|
|
592
|
+
if (!bundle.claims.some((claim) => claim.claimType === 'builder.learn.evidence' && claim.subjectType === 'release' && claim.status === 'verified')) process.exit(1);
|
|
593
|
+
NODE
|
|
594
|
+
then
|
|
595
|
+
_pass "learning-review records verified learning.json evidence"
|
|
596
|
+
else
|
|
597
|
+
_fail "learning-review did not record durable learning.json evidence in trust.bundle"
|
|
598
|
+
fi
|
|
599
|
+
assert_public_step "learn" "" "" "completed"
|
|
600
|
+
|
|
601
|
+
echo ""
|
|
602
|
+
echo "=== PUBLIC CLI: failed verify route-back remains canonical ==="
|
|
603
|
+
ROUTE_SESSION="$PUBLIC_ROOT/acme-builder-902"
|
|
604
|
+
PUBLIC_SESSION="$ROUTE_SESSION"
|
|
605
|
+
mkdir -p "$ROUTE_SESSION"
|
|
606
|
+
printf 'Selected Work Item: acme/builder#902\n' > "$ROUTE_SESSION/acme-builder-902--pull-work.md"
|
|
607
|
+
public_flow start --artifact-root "$PUBLIC_ROOT" --flow builder.build \
|
|
608
|
+
--work-item acme/builder#902 --assignment-provider local-file --summary "Public route-back path" >/dev/null 2>&1 \
|
|
609
|
+
|| _fail "route-back workflow start failed"
|
|
610
|
+
prepare_public_artifacts
|
|
611
|
+
for expectation in pickup-probe-readiness probe-decisions-or-accepted-gaps implementation-plan implementation-scope; do
|
|
612
|
+
record_public_expectation "$expectation"
|
|
613
|
+
done
|
|
614
|
+
ROUTE_CRITIQUE_OUTPUT="$(public_review critique --session-dir "$PUBLIC_SESSION" \
|
|
615
|
+
--verdict pass \
|
|
616
|
+
--summary "Authenticated review completed before failed verification evidence." \
|
|
617
|
+
--artifact-ref "$PUBLIC_SESSION/$(basename "$PUBLIC_SESSION")--deliver.md" \
|
|
618
|
+
--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)" \
|
|
619
|
+
|| _fail "public authenticated critique failed before failed tests-evidence: $ROUTE_CRITIQUE_OUTPUT"
|
|
620
|
+
# Seed current verified acceptance prerequisites through the private producer
|
|
621
|
+
# without synchronizing Flow. The subsequent public failed tests claim replaces
|
|
622
|
+
# the provisional passing tests check, preserves these criteria + the clean
|
|
623
|
+
# critique, and is the only attachment/evaluation for this gate visit.
|
|
624
|
+
ROUTE_TEST_COMMAND="bash checks/check-public-session.sh .kontourai/flow-agents/$(basename "$PUBLIC_SESSION")/state.json"
|
|
625
|
+
ROUTE_COMMAND_REF="$(node - "$ROUTE_TEST_COMMAND" <<'NODE'
|
|
626
|
+
const command = process.argv[2];
|
|
627
|
+
process.stdout.write(JSON.stringify({ kind: 'command', excerpt: command, summary: 'Current route-back prerequisite command.' }));
|
|
628
|
+
NODE
|
|
629
|
+
)"
|
|
630
|
+
ROUTE_CRITERION_ONE="$(node - "$ROUTE_TEST_COMMAND" <<'NODE'
|
|
631
|
+
const command = process.argv[2];
|
|
632
|
+
process.stdout.write(JSON.stringify({ id: 'AC-1', status: 'pass', evidence_refs: [{ kind: 'command', excerpt: command, summary: 'Current AC-1 prerequisite.' }] }));
|
|
633
|
+
NODE
|
|
634
|
+
)"
|
|
635
|
+
ROUTE_CRITERION_TWO="$(node - "$ROUTE_TEST_COMMAND" <<'NODE'
|
|
636
|
+
const command = process.argv[2];
|
|
637
|
+
process.stdout.write(JSON.stringify({ id: 'AC-2', status: 'pass', evidence_refs: [{ kind: 'command', excerpt: command, summary: 'Current AC-2 prerequisite.' }] }));
|
|
638
|
+
NODE
|
|
639
|
+
)"
|
|
640
|
+
ROUTE_OBSERVED="$(node - "$ROUTE_TEST_COMMAND" <<'NODE'
|
|
641
|
+
const command = process.argv[2];
|
|
642
|
+
process.stdout.write(JSON.stringify({ command, exit_code: 0, test_count: 1, output_sha256: '0'.repeat(64) }));
|
|
643
|
+
NODE
|
|
644
|
+
)"
|
|
645
|
+
CODEX_SESSION_ID=builder-public-producers flow_agents_node "workflow-sidecar" record-gate-claim "$PUBLIC_SESSION" \
|
|
646
|
+
--expectation tests-evidence --status pass --summary "Seed complete current acceptance prerequisites before routed failure." \
|
|
647
|
+
--command "$ROUTE_TEST_COMMAND" --observed-command-json "$ROUTE_OBSERVED" \
|
|
648
|
+
--evidence-ref-json "$ROUTE_COMMAND_REF" --criterion-json "$ROUTE_CRITERION_ONE" --criterion-json "$ROUTE_CRITERION_TWO" >/dev/null 2>&1 \
|
|
649
|
+
|| _fail "failed to seed current acceptance prerequisites for routed failure"
|
|
650
|
+
record_public_expectation "tests-evidence" "fail"
|
|
651
|
+
ROUTE_REPORT="$(public_flow status --session-dir "$PUBLIC_SESSION" --json 2>/dev/null)"
|
|
652
|
+
if node - "$ROUTE_REPORT" <<'NODE'
|
|
653
|
+
const report = JSON.parse(process.argv[2]);
|
|
654
|
+
if (report.current_step !== 'execute') process.exit(1);
|
|
655
|
+
if ((report.next_action?.skills || []).join(',') !== 'execute-plan') process.exit(2);
|
|
656
|
+
if (!/attempt 1\/3 returned to `execute` for `implementation_defect`/.test(report.next_action?.summary || '')) process.exit(3);
|
|
657
|
+
NODE
|
|
658
|
+
then
|
|
659
|
+
_pass "complete failed verify evidence routes back through Flow once to execute for implementation_defect"
|
|
660
|
+
else
|
|
661
|
+
_fail "public failed-verify route-back was not projected correctly: $ROUTE_REPORT"
|
|
662
|
+
fi
|
|
663
|
+
|
|
664
|
+
echo ""
|
|
665
|
+
echo "=== PUBLIC CLI: complete builder.shape path when supported ==="
|
|
666
|
+
SHAPE_SESSION="$PUBLIC_ROOT/builder-shape-903"
|
|
667
|
+
PUBLIC_SESSION="$SHAPE_SESSION"
|
|
668
|
+
SHAPE_START_OUTPUT="$(public_flow start --artifact-root "$PUBLIC_ROOT" --flow builder.shape \
|
|
669
|
+
--task-slug builder-shape-903 --summary "Shape public producer path" 2>&1)"
|
|
670
|
+
if [ "$?" -ne 0 ]; then
|
|
671
|
+
if printf '%s' "$SHAPE_START_OUTPUT" | rg -q 'supports only|unsupported.*builder\.shape|Unknown workflow'; then
|
|
672
|
+
_pass "public builder.shape path is deferred until the installed runtime exposes it"
|
|
673
|
+
else
|
|
674
|
+
_fail "public builder.shape start failed unexpectedly: $SHAPE_START_OUTPUT"
|
|
675
|
+
fi
|
|
676
|
+
else
|
|
677
|
+
assert_public_shape_step() {
|
|
678
|
+
local step="$1" skills="$2" status="${3:-active}"
|
|
679
|
+
local report
|
|
680
|
+
report="$(public_flow status --session-dir "$SHAPE_SESSION" --json 2>/dev/null)" || {
|
|
681
|
+
_fail "public shape status failed at $step"
|
|
682
|
+
return
|
|
683
|
+
}
|
|
684
|
+
if node - "$report" "$step" "$skills" "$status" <<'NODE'
|
|
685
|
+
const [reportText, step, skills, status] = process.argv.slice(2);
|
|
686
|
+
const report = JSON.parse(reportText);
|
|
687
|
+
const statusMatches = status === 'active-or-completed'
|
|
688
|
+
? ['active', 'completed'].includes(report.status)
|
|
689
|
+
: status === 'active-or-blocked'
|
|
690
|
+
? ['active', 'blocked'].includes(report.status)
|
|
691
|
+
: report.status === status;
|
|
692
|
+
if (report.definition_id !== 'builder.shape' || report.current_step !== step || !statusMatches) process.exit(1);
|
|
693
|
+
if ((report.next_action?.skills || []).join(',') !== skills) process.exit(2);
|
|
694
|
+
NODE
|
|
695
|
+
then
|
|
696
|
+
_pass "public shape run projects $step to ${skills:-no skill}"
|
|
697
|
+
else
|
|
698
|
+
_fail "public shape projection mismatch at $step: $report"
|
|
699
|
+
fi
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
prepare_public_artifacts
|
|
703
|
+
assert_public_shape_step "shape" "idea-to-backlog" "active-or-blocked"
|
|
704
|
+
for expectation in shaped-problem shaped-outcome shaped-constraints shaped-non-goals shaped-success shaped-risk; do
|
|
705
|
+
record_public_expectation "$expectation"
|
|
706
|
+
done
|
|
707
|
+
assert_public_shape_step "breakdown" "idea-to-backlog"
|
|
708
|
+
record_public_expectation "slices-defined"
|
|
709
|
+
assert_public_shape_step "file-issues" "idea-to-backlog"
|
|
710
|
+
record_public_expectation "work-items-filed"
|
|
711
|
+
assert_public_shape_step "shape-done" "" "active-or-completed"
|
|
712
|
+
fi
|
|
713
|
+
|
|
390
714
|
# ─── Summary ──────────────────────────────────────────────────────────────────
|
|
391
715
|
echo ""
|
|
392
716
|
if [ "$errors" -eq 0 ]; then
|
|
393
|
-
echo "Builder step producer tests passed (
|
|
717
|
+
echo "Builder step producer tests passed (legacy tamper checks plus full public happy path and route-back)."
|
|
394
718
|
exit 0
|
|
395
719
|
fi
|
|
396
720
|
echo "Builder step producer tests FAILED: $errors issue(s)."
|