@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
|
@@ -36,6 +36,15 @@ WRITER="workflow-sidecar"
|
|
|
36
36
|
VALIDATOR="validate-workflow-artifacts"
|
|
37
37
|
ARTIFACT_DIR="$TMPDIR_EVAL/repo/.kontourai/flow-agents/auto-sidecars"
|
|
38
38
|
mkdir -p "$ARTIFACT_DIR"
|
|
39
|
+
# Every direct critique write must identify a review lane. Individual focused cases below
|
|
40
|
+
# additionally prove local artifact hashing and stale-target rejection.
|
|
41
|
+
CRITIQUE_LANE='{"id":"code-review","status":"pass","summary":"Fixture code review completed.","evidence_refs":[{"kind":"external","url":"https://example.invalid/review-fixture","summary":"Fixture review evidence."}]}'
|
|
42
|
+
|
|
43
|
+
canonical_review_target() {
|
|
44
|
+
local session_dir="$1"
|
|
45
|
+
local suffix="${session_dir#*/.kontourai/flow-agents/}"
|
|
46
|
+
printf '.kontourai/flow-agents/%s/%s--deliver.md' "$suffix" "$(basename "$session_dir")"
|
|
47
|
+
}
|
|
39
48
|
|
|
40
49
|
DEFAULT_ROOT_REPO="$TMPDIR_EVAL/default-root-repo"
|
|
41
50
|
mkdir -p "$DEFAULT_ROOT_REPO"
|
|
@@ -951,12 +960,12 @@ else
|
|
|
951
960
|
_fail "sidecar writer evidence failed: $(cat "$TMPDIR_EVAL/evidence.out" "$TMPDIR_EVAL/evidence.err")"
|
|
952
961
|
fi
|
|
953
962
|
|
|
954
|
-
#
|
|
955
|
-
#
|
|
956
|
-
if rg -q '"status": "verified"' "$ARTIFACT_DIR/state.json" && [[ -f "$ARTIFACT_DIR/trust.bundle" ]] && node -e 'const fs=require("fs"); const b=JSON.parse(fs.readFileSync(process.argv[1],"utf8")); const ac=b.claims.filter(c=>c.claimType==="workflow.acceptance.criterion"); if(ac.length===0) throw new Error("no acceptance criterion claims in bundle"); if(ac.some(c=>c.value
|
|
957
|
-
_pass "sidecar writer
|
|
963
|
+
# A generic evidence write cannot fabricate acceptance success. Criteria remain pending until a
|
|
964
|
+
# passing tests-evidence gate claim supplies one structured proof per declared criterion.
|
|
965
|
+
if rg -q '"status": "verified"' "$ARTIFACT_DIR/state.json" && [[ -f "$ARTIFACT_DIR/trust.bundle" ]] && node -e 'const fs=require("fs"); const b=JSON.parse(fs.readFileSync(process.argv[1],"utf8")); const ac=b.claims.filter(c=>c.claimType==="workflow.acceptance.criterion"); if(ac.length===0) throw new Error("no acceptance criterion claims in bundle"); if(ac.some(c=>c.value==="pass")) throw new Error("generic evidence fabricated acceptance pass: "+JSON.stringify(ac.map(c=>c.value)));' "$ARTIFACT_DIR/trust.bundle" 2>/dev/null; then
|
|
966
|
+
_pass "sidecar writer preserves unverified acceptance criteria during generic evidence writes"
|
|
958
967
|
else
|
|
959
|
-
_fail "sidecar writer did not
|
|
968
|
+
_fail "sidecar writer did not preserve state and bundle acceptance evidence correctly"
|
|
960
969
|
fi
|
|
961
970
|
|
|
962
971
|
# ─── WS8 (ADR 0020) AC1: producer evidence classification ─────────────────────
|
|
@@ -1461,7 +1470,8 @@ if flow_agents_node "$WRITER" record-critique "$ARTIFACT_DIR" \
|
|
|
1461
1470
|
--reviewer tool-code-reviewer \
|
|
1462
1471
|
--verdict pass \
|
|
1463
1472
|
--summary "No blocking findings." \
|
|
1464
|
-
--artifact-ref
|
|
1473
|
+
--artifact-ref "$(canonical_review_target "$ARTIFACT_DIR")" \
|
|
1474
|
+
--lane-json "$CRITIQUE_LANE" \
|
|
1465
1475
|
--timestamp "2026-05-09T00:02:00Z" >"$TMPDIR_EVAL/critique.out" 2>"$TMPDIR_EVAL/critique.err"; then
|
|
1466
1476
|
_pass "sidecar writer records passing critique"
|
|
1467
1477
|
else
|
|
@@ -1486,6 +1496,8 @@ FLOW_AGENTS_WORKFLOW_SIDECAR_LOCK_DELAY=0.2 flow_agents_node "$WRITER" record-cr
|
|
|
1486
1496
|
--reviewer tool-code-reviewer \
|
|
1487
1497
|
--verdict pass \
|
|
1488
1498
|
--summary "Concurrent review A passed." \
|
|
1499
|
+
--artifact-ref "$(canonical_review_target "$CONCURRENT_DIR")" \
|
|
1500
|
+
--lane-json "$CRITIQUE_LANE" \
|
|
1489
1501
|
--timestamp "2026-05-09T00:02:00Z" >"$TMPDIR_EVAL/concurrent-a.out" 2>"$TMPDIR_EVAL/concurrent-a.err" &
|
|
1490
1502
|
pid_a=$!
|
|
1491
1503
|
FLOW_AGENTS_WORKFLOW_SIDECAR_LOCK_DELAY=0.2 flow_agents_node "$WRITER" record-critique "$CONCURRENT_DIR" \
|
|
@@ -1493,6 +1505,8 @@ FLOW_AGENTS_WORKFLOW_SIDECAR_LOCK_DELAY=0.2 flow_agents_node "$WRITER" record-cr
|
|
|
1493
1505
|
--reviewer tool-code-reviewer \
|
|
1494
1506
|
--verdict pass \
|
|
1495
1507
|
--summary "Concurrent review B passed." \
|
|
1508
|
+
--artifact-ref "$(canonical_review_target "$CONCURRENT_DIR")" \
|
|
1509
|
+
--lane-json "$CRITIQUE_LANE" \
|
|
1496
1510
|
--timestamp "2026-05-09T00:02:01Z" >"$TMPDIR_EVAL/concurrent-b.out" 2>"$TMPDIR_EVAL/concurrent-b.err" &
|
|
1497
1511
|
pid_b=$!
|
|
1498
1512
|
wait "$pid_a"
|
|
@@ -2167,14 +2181,13 @@ if flow_agents_node "$WRITER" dogfood-pass \
|
|
|
2167
2181
|
--require-critique \
|
|
2168
2182
|
--critique-id dogfood-clean-review \
|
|
2169
2183
|
--critique-verdict pass \
|
|
2170
|
-
--critique-summary "New critique is clean
|
|
2171
|
-
--
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
_pass "dogfood-pass rejects existing dirty critique before partial evidence writes"
|
|
2184
|
+
--critique-summary "New bundle critique is clean; legacy residue is ignored." \
|
|
2185
|
+
--artifact-ref "$(canonical_review_target "$DIRTY_CRITIQUE_DOGFOOD_DIR")" \
|
|
2186
|
+
--lane-json "$CRITIQUE_LANE" \
|
|
2187
|
+
--summary "Legacy critique.json cannot block bundle-only evidence." >"$TMPDIR_EVAL/dogfood-existing-dirty-critique.out" 2>&1; then
|
|
2188
|
+
_pass "dogfood-pass ignores a dirty legacy critique.json and records a clean bundle critique"
|
|
2176
2189
|
else
|
|
2177
|
-
_fail "dogfood-pass
|
|
2190
|
+
_fail "dogfood-pass let legacy critique.json wedge bundle-only completion: $(cat "$TMPDIR_EVAL/dogfood-existing-dirty-critique.out")"
|
|
2178
2191
|
fi
|
|
2179
2192
|
|
|
2180
2193
|
FAILED_DOGFOOD_DIR="$TMPDIR_EVAL/repo/.kontourai/flow-agents/dogfood-failed-pass"
|
|
@@ -2194,6 +2207,8 @@ if flow_agents_node "$WRITER" dogfood-pass \
|
|
|
2194
2207
|
--critique-id dogfood-failed-review \
|
|
2195
2208
|
--critique-verdict fail \
|
|
2196
2209
|
--critique-summary "Failed critique should be recorded for routing." \
|
|
2210
|
+
--artifact-ref "$(canonical_review_target "$FAILED_DOGFOOD_DIR")" \
|
|
2211
|
+
--lane-json "$CRITIQUE_LANE" \
|
|
2197
2212
|
--finding-json '{"id":"failed-dogfood-finding","severity":"high","status":"open","description":"Failed dogfood finding remains open."}' \
|
|
2198
2213
|
--summary "Dogfood pass failed and should route back to execution." \
|
|
2199
2214
|
--timestamp "2026-05-09T00:04:30Z" >"$TMPDIR_EVAL/dogfood-failed-pass.out" 2>"$TMPDIR_EVAL/dogfood-failed-pass.err"; then
|
|
@@ -2232,6 +2247,8 @@ if flow_agents_node "$WRITER" dogfood-pass \
|
|
|
2232
2247
|
--reviewer tool-code-reviewer \
|
|
2233
2248
|
--critique-verdict pass \
|
|
2234
2249
|
--critique-summary "Dogfood critique passed." \
|
|
2250
|
+
--artifact-ref "$(canonical_review_target "$DOGFOOD_DIR")" \
|
|
2251
|
+
--lane-json "$CRITIQUE_LANE" \
|
|
2235
2252
|
--learning-record-json '{"id":"dogfood-learning","source_refs":["evidence.json","critique.json"],"outcome":"success","facts":["Dogfood pass command recorded evidence and critique."],"interpretation":"Dogfood pass can close a clean local loop.","routing":[{"target":"none","action":"No follow-up required.","status":"completed"}],"correction":{"needed":false,"evidence":"Evidence, critique, and learning matched intended dogfood behavior."}}' \
|
|
2236
2253
|
--learning-summary "Dogfood command learning recorded." \
|
|
2237
2254
|
--summary "Dogfood pass completed." \
|
|
@@ -2291,6 +2308,8 @@ if flow_agents_node "$WRITER" dogfood-pass \
|
|
|
2291
2308
|
--reviewer tool-code-reviewer \
|
|
2292
2309
|
--critique-verdict pass \
|
|
2293
2310
|
--critique-summary "Dogfood release critique passed." \
|
|
2311
|
+
--artifact-ref "$(canonical_review_target "$DOGFOOD_DIR")" \
|
|
2312
|
+
--lane-json "$CRITIQUE_LANE" \
|
|
2294
2313
|
--release-decision merge \
|
|
2295
2314
|
--release-scope "Dogfood pass release readiness." \
|
|
2296
2315
|
--release-summary "Dogfood pass can record release readiness after clean evidence and critique." \
|
|
@@ -2585,7 +2604,9 @@ if flow_agents_node "$WRITER" record-critique "$BAD_DIR" \
|
|
|
2585
2604
|
--reviewer tool-code-reviewer \
|
|
2586
2605
|
--verdict pass \
|
|
2587
2606
|
--summary "Open finding should fail." \
|
|
2607
|
+
--artifact-ref "$(canonical_review_target "$BAD_DIR")" \
|
|
2588
2608
|
--finding-json '{"id":"open-medium","severity":"medium","status":"open","description":"Open finding."}' \
|
|
2609
|
+
--lane-json "$CRITIQUE_LANE" \
|
|
2589
2610
|
--timestamp "2026-05-09T00:02:00Z" >"$TMPDIR_EVAL/bad-critique.out" 2>&1; then
|
|
2590
2611
|
_fail "sidecar writer should reject open critique findings"
|
|
2591
2612
|
elif rg -q 'required critique must pass' "$TMPDIR_EVAL/bad-critique.out"; then
|
|
@@ -2734,6 +2755,8 @@ flow_agents_node "$WRITER" record-critique "$TB_CRITIQUE_DIR" \
|
|
|
2734
2755
|
--reviewer tool-code-reviewer \
|
|
2735
2756
|
--verdict fail \
|
|
2736
2757
|
--summary "Critique failed — blocking finding." \
|
|
2758
|
+
--artifact-ref "$(canonical_review_target "$TB_CRITIQUE_DIR")" \
|
|
2759
|
+
--lane-json "$CRITIQUE_LANE" \
|
|
2737
2760
|
--timestamp "2026-05-09T00:02:00Z" >"$TMPDIR_EVAL/tb-critique-fail.out" 2>"$TMPDIR_EVAL/tb-critique-fail.err" || true
|
|
2738
2761
|
|
|
2739
2762
|
# Record a passing critique (verdict pass, no open findings → claim status verified)
|
|
@@ -2742,6 +2765,8 @@ if flow_agents_node "$WRITER" record-critique "$TB_CRITIQUE_DIR" \
|
|
|
2742
2765
|
--reviewer tool-code-reviewer \
|
|
2743
2766
|
--verdict pass \
|
|
2744
2767
|
--summary "Critique passed — no blocking findings." \
|
|
2768
|
+
--artifact-ref "$(canonical_review_target "$TB_CRITIQUE_DIR")" \
|
|
2769
|
+
--lane-json "$CRITIQUE_LANE" \
|
|
2745
2770
|
--timestamp "2026-05-09T00:02:30Z" >"$TMPDIR_EVAL/tb-critique-pass.out" 2>"$TMPDIR_EVAL/tb-critique-pass.err" \
|
|
2746
2771
|
&& [[ -f "$TB_CRITIQUE_DIR/trust.bundle" ]]; then
|
|
2747
2772
|
if node --input-type=module <<NODEOF 2>"$TMPDIR_EVAL/tb-critique-assert.err"
|
|
@@ -2887,6 +2912,8 @@ if flow_agents_node "$WRITER" record-critique "$TB_UNSTAMPED_DIR" \
|
|
|
2887
2912
|
--reviewer tool-code-reviewer \
|
|
2888
2913
|
--verdict pass \
|
|
2889
2914
|
--summary "Should never be recorded -- the bundle is unstamped." \
|
|
2915
|
+
--artifact-ref "$(canonical_review_target "$TB_UNSTAMPED_DIR")" \
|
|
2916
|
+
--lane-json "$CRITIQUE_LANE" \
|
|
2890
2917
|
--timestamp "2026-05-09T00:02:00Z" >"$TMPDIR_EVAL/tb-unstamped-critique.out" 2>"$TMPDIR_EVAL/tb-unstamped-critique.err"; then
|
|
2891
2918
|
_fail "record-critique should refuse to read an unstamped (pre-#344) trust.bundle, not silently reclassify it by claimType"
|
|
2892
2919
|
elif rg -q 'pre-supersession trust\.bundle' "$TMPDIR_EVAL/tb-unstamped-critique.out" "$TMPDIR_EVAL/tb-unstamped-critique.err" \
|
|
@@ -3204,7 +3231,7 @@ cp "$ARTIFACT_DIR/auto-sidecars--deliver.md" "$TB_FO_DIR/failopen--deliver.md"
|
|
|
3204
3231
|
flow_agents_node "$WRITER" init-plan "$TB_FO_DIR/failopen--deliver.md" --task-slug failopen --source-request x --summary y --next-action z --timestamp "2026-05-09T00:00:00Z" >/dev/null 2>&1
|
|
3205
3232
|
flow_agents_node "$WRITER" record-evidence "$TB_FO_DIR" --verdict pass --check-json '{"id":"c1","kind":"test","status":"pass","summary":"s"}' --timestamp "2026-05-09T00:01:00Z" >/dev/null 2>&1
|
|
3206
3233
|
# With Surface forced-unavailable, record-critique MUST fail (non-zero), not silently drop the critique.
|
|
3207
|
-
if FLOW_AGENTS_SURFACE_UNAVAILABLE=1 flow_agents_node "$WRITER" record-critique "$TB_FO_DIR" --id rev-fo --reviewer r --verdict pass --summary fo --timestamp "2026-05-09T00:02:00Z" >"$TMPDIR_EVAL/failopen.out" 2>&1; then
|
|
3234
|
+
if FLOW_AGENTS_SURFACE_UNAVAILABLE=1 flow_agents_node "$WRITER" record-critique "$TB_FO_DIR" --id rev-fo --reviewer r --verdict pass --summary fo --artifact-ref "$(canonical_review_target "$TB_FO_DIR")" --lane-json "$CRITIQUE_LANE" --timestamp "2026-05-09T00:02:00Z" >"$TMPDIR_EVAL/failopen.out" 2>&1; then
|
|
3208
3235
|
_fail "record-critique fail-opened (exit 0) when Surface unavailable — SILENT DATA LOSS: $(cat "$TMPDIR_EVAL/failopen.out")"
|
|
3209
3236
|
elif grep -qiE "was NOT written|not persisted" "$TMPDIR_EVAL/failopen.out"; then
|
|
3210
3237
|
_pass "bundle-writers fail loudly (no silent data loss) when Surface unavailable (#156)"
|
|
@@ -3402,7 +3429,7 @@ if flow_agents_node "$WRITER" ensure-session \
|
|
|
3402
3429
|
--summary "Should fail." \
|
|
3403
3430
|
--timestamp "2026-06-25T00:00:06Z" >"$TMPDIR_EVAL/wi-bad-slash.out" 2>&1; then
|
|
3404
3431
|
_fail "ensure-session should reject work-item ref without # separator"
|
|
3405
|
-
elif grep -q 'owner/repo#id
|
|
3432
|
+
elif grep -q 'provider-neutral provider:id ref or owner/repo#numeric-id' "$TMPDIR_EVAL/wi-bad-slash.out"; then
|
|
3406
3433
|
_pass "ensure-session rejects work-item ref without # separator"
|
|
3407
3434
|
else
|
|
3408
3435
|
_fail "malformed ref rejection message was unexpected: $(cat "$TMPDIR_EVAL/wi-bad-slash.out")"
|
|
@@ -3532,11 +3559,13 @@ else
|
|
|
3532
3559
|
fi
|
|
3533
3560
|
|
|
3534
3561
|
# ─── AC1/AC10: record-gate-claim (pull-work-gate/selected-work) with --command ───────────────
|
|
3562
|
+
printf '%s\n' "# Pull Work Report" "" "Selected Work Item: local:${COMPOSE_SLUG}" > "$COMPOSE_DIR/${COMPOSE_SLUG}--pull-work.md"
|
|
3535
3563
|
if flow_agents_node "$WRITER" record-gate-claim "$COMPOSE_DIR" \
|
|
3536
3564
|
--actor compose-actor \
|
|
3537
3565
|
--status pass \
|
|
3538
3566
|
--summary "Work item selected for compose session" \
|
|
3539
|
-
--command "
|
|
3567
|
+
--command "test -f .kontourai/flow-agents/compose-270/compose-270--pull-work.md" \
|
|
3568
|
+
--evidence-ref-json '{"kind":"artifact","file":".kontourai/flow-agents/compose-270/compose-270--pull-work.md","summary":"Concrete pull-work selection report naming local:compose-270."}' \
|
|
3540
3569
|
--timestamp "2026-07-05T09:07:00Z" >"$TMPDIR_EVAL/compose-gate1.out" 2>"$TMPDIR_EVAL/compose-gate1.err"; then
|
|
3541
3570
|
_pass "compose: record-gate-claim (selected-work) with --command succeeds"
|
|
3542
3571
|
else
|
|
@@ -3554,7 +3583,7 @@ if (!buildClaim || !manualClaim) { process.stderr.write('record-gate-claim clobb
|
|
|
3554
3583
|
if (!gateClaim) { process.stderr.write('gate claim missing metadata.gate_claim stamp\n'); process.exit(1); }
|
|
3555
3584
|
if (gateClaim.claimType !== 'builder.pull-work.selected' || gateClaim.subjectType !== 'work-item') { process.stderr.write('gate claim typed incorrectly: ' + gateClaim.claimType + '/' + gateClaim.subjectType + '\n'); process.exit(1); }
|
|
3556
3585
|
const ev = bundle.evidence.find((e) => e.claimId === gateClaim.id);
|
|
3557
|
-
if (!ev || !ev.execution || ev.execution.label !== '
|
|
3586
|
+
if (!ev || !ev.execution || ev.execution.label !== 'test -f .kontourai/flow-agents/compose-270/compose-270--pull-work.md') { process.stderr.write('AC10: --command did not stamp execution.label on the gate claim evidence\n'); process.exit(1); }
|
|
3558
3587
|
if (claims.length !== 4) { process.stderr.write('expected exactly 4 claims after record-gate-claim (2 checks + 1 acceptance + 1 gate claim), got ' + claims.length + '\n'); process.exit(1); }
|
|
3559
3588
|
NODEOF
|
|
3560
3589
|
then
|
|
@@ -3581,11 +3610,15 @@ fi
|
|
|
3581
3610
|
|
|
3582
3611
|
# ─── AC1: a SECOND gate claim against a DIFFERENT expectation (plan-gate/implementation-plan) ──
|
|
3583
3612
|
# is additive, not a replacement, of the FIRST gate claim (pull-work-gate/selected-work) ───────
|
|
3613
|
+
printf '%s\n' "# Implementation Plan" "" "Files: evals/integration/test_workflow_sidecar_writer.sh" "Evidence: acceptance.json, handoff.json" > "$COMPOSE_DIR/${COMPOSE_SLUG}--plan-work.md"
|
|
3584
3614
|
if flow_agents_node "$WRITER" record-gate-claim "$COMPOSE_DIR" \
|
|
3585
3615
|
--actor compose-actor \
|
|
3586
3616
|
--status pass \
|
|
3587
3617
|
--summary "Implementation plan recorded for compose session" \
|
|
3588
3618
|
--expectation implementation-plan \
|
|
3619
|
+
--evidence-ref-json '{"kind":"artifact","file":".kontourai/flow-agents/compose-270/compose-270--plan-work.md","summary":"Concrete plan-work report for the implementation plan."}' \
|
|
3620
|
+
--evidence-ref-json '{"kind":"artifact","file":".kontourai/flow-agents/compose-270/acceptance.json","summary":"Declared acceptance criteria for the implementation plan."}' \
|
|
3621
|
+
--evidence-ref-json '{"kind":"artifact","file":".kontourai/flow-agents/compose-270/handoff.json","summary":"Plan handoff for the implementation plan."}' \
|
|
3589
3622
|
--timestamp "2026-07-05T09:07:30Z" >"$TMPDIR_EVAL/compose-gate2.out" 2>"$TMPDIR_EVAL/compose-gate2.err"; then
|
|
3590
3623
|
_pass "compose: second record-gate-claim (different expectation, implementation-plan) succeeds"
|
|
3591
3624
|
else
|
|
@@ -3631,6 +3664,8 @@ if flow_agents_node "$WRITER" record-critique "$COMPOSE_DIR" \
|
|
|
3631
3664
|
--reviewer compose-reviewer \
|
|
3632
3665
|
--verdict pass \
|
|
3633
3666
|
--summary "Compose review looks good" \
|
|
3667
|
+
--artifact-ref "$(canonical_review_target "$COMPOSE_DIR")" \
|
|
3668
|
+
--lane-json "$CRITIQUE_LANE" \
|
|
3634
3669
|
--timestamp "2026-07-05T09:09:00Z" >"$TMPDIR_EVAL/compose-critique.out" 2>"$TMPDIR_EVAL/compose-critique.err"; then
|
|
3635
3670
|
_pass "compose: record-critique rebuilds the bundle at the new active step (merge-ready)"
|
|
3636
3671
|
else
|
|
@@ -3665,6 +3700,180 @@ else
|
|
|
3665
3700
|
_fail "AC2: gate-claim-typing-survives-rebuild assertion failed: $(cat "$TMPDIR_EVAL/compose-ac2-assert.err")"
|
|
3666
3701
|
fi
|
|
3667
3702
|
|
|
3703
|
+
# Legacy critique.json is unsupported historical residue. It must neither alter the
|
|
3704
|
+
# authoritative bundle nor create a live blocker during a subsequent critique write.
|
|
3705
|
+
LEGACY_CRITIQUE_PROJECT="$TMPDIR_EVAL/legacy-critique-project"
|
|
3706
|
+
LEGACY_CRITIQUE_ROOT="$LEGACY_CRITIQUE_PROJECT/.kontourai/flow-agents"
|
|
3707
|
+
mkdir -p "$LEGACY_CRITIQUE_PROJECT/.kontourai"
|
|
3708
|
+
cp -r "$COMPOSE_ROOT" "$LEGACY_CRITIQUE_ROOT"
|
|
3709
|
+
LEGACY_CRITIQUE_DIR="$LEGACY_CRITIQUE_ROOT/$COMPOSE_SLUG"
|
|
3710
|
+
cat > "$LEGACY_CRITIQUE_DIR/critique.json" <<'JSON'
|
|
3711
|
+
{
|
|
3712
|
+
"critiques": [
|
|
3713
|
+
{"id":"compose-review","reviewer":"legacy-reviewer","reviewed_at":"2026-07-05T08:00:00Z","verdict":"fail","summary":"Stale legacy duplicate must not replace the bundle record.","findings":[]},
|
|
3714
|
+
{"id":"legacy-only-review","reviewer":"legacy-reviewer","reviewed_at":"2026-07-05T08:01:00Z","verdict":"not_verified","summary":"Legacy-only migration record.","findings":[]}
|
|
3715
|
+
]
|
|
3716
|
+
}
|
|
3717
|
+
JSON
|
|
3718
|
+
if flow_agents_node "$WRITER" record-critique "$LEGACY_CRITIQUE_DIR" \
|
|
3719
|
+
--id bundle-only-review \
|
|
3720
|
+
--reviewer compose-reviewer \
|
|
3721
|
+
--verdict pass \
|
|
3722
|
+
--summary "Bundle-only review looks good" \
|
|
3723
|
+
--artifact-ref "$(canonical_review_target "$LEGACY_CRITIQUE_DIR")" \
|
|
3724
|
+
--lane-json "$CRITIQUE_LANE" \
|
|
3725
|
+
--timestamp "2026-07-05T09:09:30Z" >"$TMPDIR_EVAL/legacy-critique.out" 2>"$TMPDIR_EVAL/legacy-critique.err"; then
|
|
3726
|
+
if node --input-type=module <<NODEOF 2>"$TMPDIR_EVAL/legacy-critique-assert.err"
|
|
3727
|
+
import { readFileSync } from 'node:fs';
|
|
3728
|
+
const bundle = JSON.parse(readFileSync('${LEGACY_CRITIQUE_DIR}/trust.bundle', 'utf8'));
|
|
3729
|
+
const critiques = bundle.claims.filter((claim) => claim.metadata?.origin === 'critique');
|
|
3730
|
+
const byId = new Map(critiques.map((claim) => [String(claim.subjectId).split('/').pop(), claim]));
|
|
3731
|
+
if (critiques.length !== 2 || byId.size !== 2) process.exit(1);
|
|
3732
|
+
if (byId.get('compose-review')?.value !== 'pass') process.exit(2);
|
|
3733
|
+
if (byId.has('legacy-only-review')) process.exit(3);
|
|
3734
|
+
if (byId.get('bundle-only-review')?.value !== 'pass') process.exit(4);
|
|
3735
|
+
NODEOF
|
|
3736
|
+
then
|
|
3737
|
+
_pass "legacy critique.json cannot alter or wedge authoritative bundle critiques"
|
|
3738
|
+
else
|
|
3739
|
+
_fail "legacy critique isolation assertion failed: $(cat "$TMPDIR_EVAL/legacy-critique-assert.err")"
|
|
3740
|
+
fi
|
|
3741
|
+
else
|
|
3742
|
+
_fail "legacy critique isolation write failed: $(cat "$TMPDIR_EVAL/legacy-critique.out" "$TMPDIR_EVAL/legacy-critique.err")"
|
|
3743
|
+
fi
|
|
3744
|
+
|
|
3745
|
+
# ─── Tests-evidence writer: immutable criteria, multiple observed commands, non-vacuous scripts ──
|
|
3746
|
+
MULTI_PROJECT="$TMPDIR_EVAL/multi-observed-project"
|
|
3747
|
+
MULTI_ROOT="$MULTI_PROJECT/.kontourai/flow-agents"
|
|
3748
|
+
MULTI_SLUG="multi-observed"
|
|
3749
|
+
MULTI_DIR="$MULTI_ROOT/$MULTI_SLUG"
|
|
3750
|
+
mkdir -p "$MULTI_ROOT" "$MULTI_PROJECT/checks" "$MULTI_PROJECT/test"
|
|
3751
|
+
printf '#!/usr/bin/env bash\nset -eu\ntest -f "$1"\nprintf "1..1\\nok 1 - fixture exists\\n"\n' > "$MULTI_PROJECT/checks/test-one.sh"
|
|
3752
|
+
printf '#!/usr/bin/env bash\nset -eu\ntest -f "$1"\nprintf "1..1\\nok 1 - fixture exists\\n"\n' > "$MULTI_PROJECT/checks/test-two.sh"
|
|
3753
|
+
chmod +x "$MULTI_PROJECT/checks/test-one.sh" "$MULTI_PROJECT/checks/test-two.sh"
|
|
3754
|
+
printf 'import test from "node:test";\nimport assert from "node:assert/strict";\ntest("fixture", () => assert.equal(1, 1));\n' > "$MULTI_PROJECT/test/sample.test.mjs"
|
|
3755
|
+
cat > "$MULTI_PROJECT/package.json" <<'JSON'
|
|
3756
|
+
{"scripts":{"test":"true","check":"echo check"}}
|
|
3757
|
+
JSON
|
|
3758
|
+
flow_agents_node "$WRITER" ensure-session \
|
|
3759
|
+
--artifact-root "$MULTI_ROOT" --task-slug "$MULTI_SLUG" --actor multi-observed-actor \
|
|
3760
|
+
--title "Multiple observed commands" --summary "Verify immutable acceptance criteria." \
|
|
3761
|
+
--criterion "First immutable criterion" --criterion "Second immutable criterion" \
|
|
3762
|
+
--timestamp "2026-07-11T11:00:00Z" >"$TMPDIR_EVAL/multi-seed.out" 2>"$TMPDIR_EVAL/multi-seed.err"
|
|
3763
|
+
flow_agents_node "$WRITER" advance-state "$MULTI_DIR" \
|
|
3764
|
+
--actor multi-observed-actor --status in_progress --phase verification \
|
|
3765
|
+
--summary "Move fixture to tests evidence." --next-action "Verify commands." \
|
|
3766
|
+
--flow-definition builder.build --timestamp "2026-07-11T11:00:10Z" >"$TMPDIR_EVAL/multi-advance.out" 2>"$TMPDIR_EVAL/multi-advance.err"
|
|
3767
|
+
printf '# Plan evidence\n' > "$MULTI_DIR/$MULTI_SLUG--plan-work.md"
|
|
3768
|
+
if flow_agents_node "$WRITER" record-critique "$MULTI_DIR" \
|
|
3769
|
+
--id multi-review --reviewer multi-reviewer --verdict pass --summary "Review completed." \
|
|
3770
|
+
--artifact-ref "$(canonical_review_target "$MULTI_DIR")" --lane-json "$CRITIQUE_LANE" \
|
|
3771
|
+
--timestamp "2026-07-11T11:00:20Z" >"$TMPDIR_EVAL/multi-critique.out" 2>"$TMPDIR_EVAL/multi-critique.err"; then
|
|
3772
|
+
_pass "tests-evidence fixture records a clean critique with a record-time snapshot"
|
|
3773
|
+
else
|
|
3774
|
+
_fail "tests-evidence fixture critique failed: $(cat "$TMPDIR_EVAL/multi-critique.out" "$TMPDIR_EVAL/multi-critique.err")"
|
|
3775
|
+
fi
|
|
3776
|
+
|
|
3777
|
+
MULTI_ONE="bash checks/test-one.sh test/sample.test.mjs"
|
|
3778
|
+
MULTI_TWO="bash checks/test-two.sh test/sample.test.mjs"
|
|
3779
|
+
MULTI_DIGEST="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
|
3780
|
+
MULTI_REF_ONE="{\"kind\":\"command\",\"excerpt\":\"$MULTI_ONE\",\"summary\":\"First exact command.\"}"
|
|
3781
|
+
MULTI_REF_TWO="{\"kind\":\"command\",\"excerpt\":\"$MULTI_TWO\",\"summary\":\"Second exact command.\"}"
|
|
3782
|
+
MULTI_OBS_ONE="{\"command\":\"$MULTI_ONE\",\"exit_code\":0,\"test_count\":1,\"output_sha256\":\"$MULTI_DIGEST\"}"
|
|
3783
|
+
MULTI_OBS_TWO="{\"command\":\"$MULTI_TWO\",\"exit_code\":0,\"test_count\":1,\"output_sha256\":\"$MULTI_DIGEST\"}"
|
|
3784
|
+
|
|
3785
|
+
MULTI_VACUOUS_REJECTED=yes
|
|
3786
|
+
for multi_script_command in "npm test" "pnpm test" "yarn test" "bun run test"; do
|
|
3787
|
+
if flow_agents_node "$WRITER" record-gate-claim "$MULTI_DIR" \
|
|
3788
|
+
--actor multi-observed-actor --expectation tests-evidence --status pass --summary "Vacuous package script." \
|
|
3789
|
+
--command "$multi_script_command" --evidence-ref-json "$MULTI_REF_ONE" \
|
|
3790
|
+
--criterion-json "{\"id\":\"first-immutable-criterion\",\"status\":\"pass\",\"evidence_refs\":[$MULTI_REF_ONE]}" \
|
|
3791
|
+
--criterion-json "{\"id\":\"second-immutable-criterion\",\"status\":\"pass\",\"evidence_refs\":[$MULTI_REF_ONE]}" \
|
|
3792
|
+
>"$TMPDIR_EVAL/multi-vacuous.out" 2>"$TMPDIR_EVAL/multi-vacuous.err"; then
|
|
3793
|
+
MULTI_VACUOUS_REJECTED=no
|
|
3794
|
+
fi
|
|
3795
|
+
done
|
|
3796
|
+
if [ "$MULTI_VACUOUS_REJECTED" = yes ]; then
|
|
3797
|
+
_pass "tests-evidence resolves npm/pnpm/yarn/bun scripts and rejects vacuous package bodies"
|
|
3798
|
+
else
|
|
3799
|
+
_fail "tests-evidence accepted a vacuous npm/pnpm/yarn/bun package script"
|
|
3800
|
+
fi
|
|
3801
|
+
|
|
3802
|
+
cat > "$MULTI_PROJECT/package.json" <<'JSON'
|
|
3803
|
+
{"scripts":{"build":"tsc --noEmit","test":"node --test test/*.test.mjs","test:unit":"npm run build && node --test test/*.test.mjs"}}
|
|
3804
|
+
JSON
|
|
3805
|
+
if node --input-type=module - "$ROOT/build/src/cli/workflow-sidecar.js" "$MULTI_PROJECT" <<'NODE'
|
|
3806
|
+
const [modulePath, projectRoot] = process.argv.slice(2);
|
|
3807
|
+
const { isMeaningfulTestCommand } = await import(modulePath);
|
|
3808
|
+
if (!isMeaningfulTestCommand('npm test', projectRoot)) process.exit(1);
|
|
3809
|
+
if (!isMeaningfulTestCommand('npm run test:unit', projectRoot)) process.exit(2);
|
|
3810
|
+
NODE
|
|
3811
|
+
then
|
|
3812
|
+
_pass "tests-evidence accepts substantive direct and composed Node package test scripts"
|
|
3813
|
+
else
|
|
3814
|
+
_fail "tests-evidence rejected a substantive package test script"
|
|
3815
|
+
fi
|
|
3816
|
+
if flow_agents_node "$WRITER" record-critique "$MULTI_DIR" \
|
|
3817
|
+
--id multi-review --reviewer multi-reviewer --verdict pass --summary "Review refreshed after the package-script fixture changed." \
|
|
3818
|
+
--artifact-ref "$(canonical_review_target "$MULTI_DIR")" --lane-json "$CRITIQUE_LANE" \
|
|
3819
|
+
--timestamp "2026-07-11T11:00:25Z" >"$TMPDIR_EVAL/multi-critique-refresh.out" 2>"$TMPDIR_EVAL/multi-critique-refresh.err"; then
|
|
3820
|
+
_pass "tests-evidence fixture refreshes review after an intentional source change"
|
|
3821
|
+
else
|
|
3822
|
+
_fail "tests-evidence fixture failed to refresh stale review: $(cat "$TMPDIR_EVAL/multi-critique-refresh.out" "$TMPDIR_EVAL/multi-critique-refresh.err")"
|
|
3823
|
+
fi
|
|
3824
|
+
|
|
3825
|
+
if flow_agents_node "$WRITER" record-gate-claim "$MULTI_DIR" \
|
|
3826
|
+
--actor multi-observed-actor --expectation tests-evidence --status pass --summary "Rewritten criterion." \
|
|
3827
|
+
--command "$MULTI_ONE" --observed-command-json "$MULTI_OBS_ONE" --evidence-ref-json "$MULTI_REF_ONE" \
|
|
3828
|
+
--criterion-json "{\"id\":\"first-immutable-criterion\",\"description\":\"Caller rewrite.\",\"status\":\"pass\",\"evidence_refs\":[$MULTI_REF_ONE]}" \
|
|
3829
|
+
--criterion-json "{\"id\":\"second-immutable-criterion\",\"status\":\"pass\",\"evidence_refs\":[$MULTI_REF_ONE]}" \
|
|
3830
|
+
>"$TMPDIR_EVAL/multi-rewrite.out" 2>"$TMPDIR_EVAL/multi-rewrite.err"; then
|
|
3831
|
+
_fail "tests-evidence accepted caller rewriting an immutable criterion description"
|
|
3832
|
+
else
|
|
3833
|
+
_pass "tests-evidence rejects criterion description rewriting"
|
|
3834
|
+
fi
|
|
3835
|
+
|
|
3836
|
+
if flow_agents_node "$WRITER" record-gate-claim "$MULTI_DIR" \
|
|
3837
|
+
--actor multi-observed-actor --expectation tests-evidence --status pass --summary "Unknown criterion field." \
|
|
3838
|
+
--command "$MULTI_ONE" --observed-command-json "$MULTI_OBS_ONE" --evidence-ref-json "$MULTI_REF_ONE" \
|
|
3839
|
+
--criterion-json "{\"id\":\"first-immutable-criterion\",\"status\":\"pass\",\"unexpected\":true,\"evidence_refs\":[$MULTI_REF_ONE]}" \
|
|
3840
|
+
--criterion-json "{\"id\":\"second-immutable-criterion\",\"status\":\"pass\",\"evidence_refs\":[$MULTI_REF_ONE]}" \
|
|
3841
|
+
>"$TMPDIR_EVAL/multi-unknown.out" 2>"$TMPDIR_EVAL/multi-unknown.err"; then
|
|
3842
|
+
_fail "tests-evidence accepted an unknown criterion field"
|
|
3843
|
+
else
|
|
3844
|
+
_pass "tests-evidence rejects unknown criterion fields"
|
|
3845
|
+
fi
|
|
3846
|
+
|
|
3847
|
+
if flow_agents_node "$WRITER" record-gate-claim "$MULTI_DIR" \
|
|
3848
|
+
--actor multi-observed-actor --expectation tests-evidence --status pass --summary "Two exact observed commands." \
|
|
3849
|
+
--command "$MULTI_ONE" --command "$MULTI_TWO" \
|
|
3850
|
+
--observed-command-json "$MULTI_OBS_ONE" --observed-command-json "$MULTI_OBS_TWO" \
|
|
3851
|
+
--evidence-ref-json "{\"kind\":\"artifact\",\"file\":\".kontourai/flow-agents/$MULTI_SLUG/$MULTI_SLUG--plan-work.md\",\"summary\":\"Durable verification plan.\"}" \
|
|
3852
|
+
--evidence-ref-json "$MULTI_REF_ONE" --evidence-ref-json "$MULTI_REF_TWO" \
|
|
3853
|
+
--criterion-json "{\"id\":\"first-immutable-criterion\",\"status\":\"pass\",\"evidence_refs\":[$MULTI_REF_ONE]}" \
|
|
3854
|
+
--criterion-json "{\"id\":\"second-immutable-criterion\",\"status\":\"pass\",\"evidence_refs\":[$MULTI_REF_TWO]}" \
|
|
3855
|
+
--timestamp "2026-07-11T11:00:30Z" >"$TMPDIR_EVAL/multi-pass.out" 2>"$TMPDIR_EVAL/multi-pass.err"; then
|
|
3856
|
+
if node - "$MULTI_DIR/acceptance.json" "$MULTI_DIR/trust.bundle" <<'NODE'
|
|
3857
|
+
const fs = require('node:fs');
|
|
3858
|
+
const [acceptanceFile, bundleFile] = process.argv.slice(2);
|
|
3859
|
+
const acceptance = JSON.parse(fs.readFileSync(acceptanceFile, 'utf8'));
|
|
3860
|
+
if (acceptance.criteria[0].description !== 'First immutable criterion' || acceptance.criteria[1].description !== 'Second immutable criterion') process.exit(1);
|
|
3861
|
+
const bundle = JSON.parse(fs.readFileSync(bundleFile, 'utf8'));
|
|
3862
|
+
const gate = bundle.claims.find((claim) => claim.metadata?.gate_claim?.expectation_id === 'tests-evidence');
|
|
3863
|
+
const review = bundle.claims.find((claim) => claim.metadata?.origin === 'critique');
|
|
3864
|
+
if (!gate || gate.metadata?.observed_commands?.length !== 2) process.exit(2);
|
|
3865
|
+
const snapshot = review?.metadata?.review_target?.workspace_snapshot;
|
|
3866
|
+
if (!snapshot || snapshot.version !== 1 || snapshot.algorithm !== 'sha256' || typeof snapshot.digest !== 'string') process.exit(3);
|
|
3867
|
+
NODE
|
|
3868
|
+
then
|
|
3869
|
+
_pass "tests-evidence preserves immutable acceptance semantics and maps each criterion to its successful observed command"
|
|
3870
|
+
else
|
|
3871
|
+
_fail "tests-evidence multi-command or review snapshot assertion failed"
|
|
3872
|
+
fi
|
|
3873
|
+
else
|
|
3874
|
+
_fail "tests-evidence multi-command write failed: $(cat "$TMPDIR_EVAL/multi-pass.out" "$TMPDIR_EVAL/multi-pass.err")"
|
|
3875
|
+
fi
|
|
3876
|
+
|
|
3668
3877
|
# ─── AC4: compose-three-writer (five writer calls total: evidence x2, gate-claim x2, critique, ──
|
|
3669
3878
|
# then record-learning) — all claim families present and correctly typed in the final bundle ──
|
|
3670
3879
|
if flow_agents_node "$WRITER" record-learning "$COMPOSE_DIR" \
|
|
@@ -4053,7 +4262,9 @@ fi
|
|
|
4053
4262
|
# buildTrustBundle) needs them to resolve the flow definition for stamp validation. Copying only
|
|
4054
4263
|
# the session dir would silently make sessionFlowId resolve to null, which changes what's being
|
|
4055
4264
|
# tested (the "no flow definition resolvable" edge case) rather than the forged-stamp case.
|
|
4056
|
-
|
|
4265
|
+
FORGED_PROJECT="$TMPDIR_EVAL/forged-stamp-project"
|
|
4266
|
+
FORGED_ROOT="$FORGED_PROJECT/.kontourai/flow-agents"
|
|
4267
|
+
mkdir -p "$FORGED_PROJECT/.kontourai"
|
|
4057
4268
|
cp -r "$COMPOSE_ROOT" "$FORGED_ROOT"
|
|
4058
4269
|
FORGED_DIR="$FORGED_ROOT/$COMPOSE_SLUG"
|
|
4059
4270
|
|
|
@@ -4076,6 +4287,8 @@ if flow_agents_node "$WRITER" record-critique "$FORGED_DIR" \
|
|
|
4076
4287
|
--reviewer forged-stamp-tester \
|
|
4077
4288
|
--verdict pass \
|
|
4078
4289
|
--summary "Rebuild attempt against a forged gate_claim stamp" \
|
|
4290
|
+
--artifact-ref "$(canonical_review_target "$FORGED_DIR")" \
|
|
4291
|
+
--lane-json "$CRITIQUE_LANE" \
|
|
4079
4292
|
--timestamp "2026-07-05T09:12:00Z" >"$TMPDIR_EVAL/forged-critique.out" 2>"$TMPDIR_EVAL/forged-critique.err"; then
|
|
4080
4293
|
_fail "FORGED-STAMP REGRESSION: record-critique succeeded against a bundle with a forged metadata.gate_claim.expectation_id (silent re-typing fall-through, the #270 CRITICAL/HIGH defect)"
|
|
4081
4294
|
elif grep -qi "forged or corrupt" "$TMPDIR_EVAL/forged-critique.out" "$TMPDIR_EVAL/forged-critique.err" \
|
|
@@ -4089,7 +4302,9 @@ fi
|
|
|
4089
4302
|
# claim (origin:"check", check_kind:"external", kit-typed claimType) — mimicking the real
|
|
4090
4303
|
# kontourai-flow-agents-303 bundle shape (a claim recorded before the gate_claim stamp existed).
|
|
4091
4304
|
# Any rebuild must die with the re-record remedy, never silently re-type via matchExpectsEntry.
|
|
4092
|
-
|
|
4305
|
+
PRECLUSTER_PROJECT="$TMPDIR_EVAL/precluster-missing-stamp-project"
|
|
4306
|
+
PRECLUSTER_ROOT="$PRECLUSTER_PROJECT/.kontourai/flow-agents"
|
|
4307
|
+
mkdir -p "$PRECLUSTER_PROJECT/.kontourai"
|
|
4093
4308
|
cp -r "$COMPOSE_ROOT" "$PRECLUSTER_ROOT"
|
|
4094
4309
|
PRECLUSTER_DIR="$PRECLUSTER_ROOT/$COMPOSE_SLUG"
|
|
4095
4310
|
|
|
@@ -4112,6 +4327,8 @@ if flow_agents_node "$WRITER" record-critique "$PRECLUSTER_DIR" \
|
|
|
4112
4327
|
--reviewer precluster-tester \
|
|
4113
4328
|
--verdict pass \
|
|
4114
4329
|
--summary "Rebuild attempt against a pre-cluster-270 unstamped gate claim" \
|
|
4330
|
+
--artifact-ref "$(canonical_review_target "$PRECLUSTER_DIR")" \
|
|
4331
|
+
--lane-json "$CRITIQUE_LANE" \
|
|
4115
4332
|
--timestamp "2026-07-05T09:13:00Z" >"$TMPDIR_EVAL/precluster-critique.out" 2>"$TMPDIR_EVAL/precluster-critique.err"; then
|
|
4116
4333
|
_fail "PRE-CLUSTER-270 REGRESSION: record-critique succeeded against a bundle with an unstamped gate-claim-shaped claim (silent re-typing fall-through)"
|
|
4117
4334
|
elif grep -qi "pre-cluster-270 gate claim" "$TMPDIR_EVAL/precluster-critique.out" "$TMPDIR_EVAL/precluster-critique.err" \
|
|
@@ -4207,6 +4424,8 @@ if flow_agents_node "$WRITER" record-critique "$COLLISION_DIR" \
|
|
|
4207
4424
|
--reviewer collision-tester \
|
|
4208
4425
|
--verdict pass \
|
|
4209
4426
|
--summary "Rebuild after the rejected collision write — must succeed, no landmine" \
|
|
4427
|
+
--artifact-ref "$(canonical_review_target "$COLLISION_DIR")" \
|
|
4428
|
+
--lane-json "$CRITIQUE_LANE" \
|
|
4210
4429
|
--timestamp "2026-07-05T09:16:30Z" >"$TMPDIR_EVAL/collision-rebuild.out" 2>"$TMPDIR_EVAL/collision-rebuild.err"; then
|
|
4211
4430
|
_pass "#270 HIGH: a rebuild (record-critique) after the rejected collision write succeeds cleanly — no rebuild-time landmine"
|
|
4212
4431
|
else
|
|
@@ -4222,31 +4441,32 @@ UNRESOLVABLE_ROOT="$TMPDIR_EVAL/unresolvable-project/.kontourai/flow-agents"
|
|
|
4222
4441
|
UNRESOLVABLE_SLUG="unresolvable-270"
|
|
4223
4442
|
UNRESOLVABLE_DIR="$UNRESOLVABLE_ROOT/$UNRESOLVABLE_SLUG"
|
|
4224
4443
|
mkdir -p "$UNRESOLVABLE_ROOT"
|
|
4444
|
+
mkdir -p "$UNRESOLVABLE_DIR"
|
|
4445
|
+
printf '%s\n' "# Pull Work Report" "" "Selected Work Item: unresolvable:270" > "$UNRESOLVABLE_DIR/${UNRESOLVABLE_SLUG}--pull-work.md"
|
|
4225
4446
|
|
|
4226
|
-
|
|
4447
|
+
FLOW_AGENTS_ACTOR=unresolvable-actor node "$ROOT/build/src/cli.js" workflow start \
|
|
4227
4448
|
--artifact-root "$UNRESOLVABLE_ROOT" \
|
|
4228
|
-
--
|
|
4229
|
-
--
|
|
4230
|
-
--
|
|
4231
|
-
--skip-ownership-guard \
|
|
4449
|
+
--flow builder.build \
|
|
4450
|
+
--work-item unresolvable:270 \
|
|
4451
|
+
--assignment-provider local-file \
|
|
4232
4452
|
--title "Unresolvable FlowDefinition regression" \
|
|
4233
4453
|
--source-request "Regression: an unresolvable FlowDefinition must die with the dedicated cannot-be-loaded message." \
|
|
4234
4454
|
--summary "Seed session with a REAL flow so a real stamped gate claim can be recorded." \
|
|
4235
|
-
--criterion "Unresolvable FlowDefinition dies with the dedicated message"
|
|
4236
|
-
--timestamp "2026-07-05T09:17:00Z" >"$TMPDIR_EVAL/unresolvable-seed.out" 2>"$TMPDIR_EVAL/unresolvable-seed.err"
|
|
4455
|
+
--criterion "Unresolvable FlowDefinition dies with the dedicated message" >"$TMPDIR_EVAL/unresolvable-seed.out" 2>"$TMPDIR_EVAL/unresolvable-seed.err"
|
|
4237
4456
|
|
|
4238
|
-
if
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4457
|
+
if node - "$UNRESOLVABLE_DIR/trust.bundle" <<'NODEOF'
|
|
4458
|
+
const fs = require('node:fs');
|
|
4459
|
+
const bundle = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
|
|
4460
|
+
if (!bundle.claims.some((claim) => claim.metadata?.gate_claim?.expectation_id === 'selected-work')) process.exit(1);
|
|
4461
|
+
NODEOF
|
|
4462
|
+
then
|
|
4243
4463
|
_pass "#270 MEDIUM setup: real stamped gate claim recorded before breaking FlowDefinition resolution"
|
|
4244
4464
|
else
|
|
4245
|
-
_fail "#270 MEDIUM setup: record
|
|
4465
|
+
_fail "#270 MEDIUM setup: public workflow did not record a real selected-work gate claim: $(cat "$TMPDIR_EVAL/unresolvable-seed.out" "$TMPDIR_EVAL/unresolvable-seed.err")"
|
|
4246
4466
|
fi
|
|
4247
4467
|
|
|
4248
|
-
#
|
|
4249
|
-
#
|
|
4468
|
+
# Poison BOTH navigation pointers. Exact-session writers must continue to use the persisted
|
|
4469
|
+
# canonical flow_run from the session instead of treating ambient pointers as authority.
|
|
4250
4470
|
node --input-type=module <<NODEOF 2>"$TMPDIR_EVAL/unresolvable-mutate.err"
|
|
4251
4471
|
import { readFileSync, writeFileSync } from 'node:fs';
|
|
4252
4472
|
for (const f of ['${UNRESOLVABLE_ROOT}/current.json', '${UNRESOLVABLE_ROOT}/current/unresolvable-actor.json']) {
|
|
@@ -4265,14 +4485,12 @@ if flow_agents_node "$WRITER" record-critique "$UNRESOLVABLE_DIR" \
|
|
|
4265
4485
|
--reviewer unresolvable-tester \
|
|
4266
4486
|
--verdict pass \
|
|
4267
4487
|
--summary "Rebuild attempt against an unresolvable FlowDefinition" \
|
|
4488
|
+
--artifact-ref "$(canonical_review_target "$UNRESOLVABLE_DIR")" \
|
|
4489
|
+
--lane-json "$CRITIQUE_LANE" \
|
|
4268
4490
|
--timestamp "2026-07-05T09:17:30Z" >"$TMPDIR_EVAL/unresolvable-critique.out" 2>"$TMPDIR_EVAL/unresolvable-critique.err"; then
|
|
4269
|
-
|
|
4270
|
-
elif grep -qi "cannot be loaded" "$TMPDIR_EVAL/unresolvable-critique.out" "$TMPDIR_EVAL/unresolvable-critique.err" \
|
|
4271
|
-
&& grep -qi "cannot validate the gate-claim stamp" "$TMPDIR_EVAL/unresolvable-critique.out" "$TMPDIR_EVAL/unresolvable-critique.err" \
|
|
4272
|
-
&& ! grep -qi "forged or corrupt" "$TMPDIR_EVAL/unresolvable-critique.out" "$TMPDIR_EVAL/unresolvable-critique.err"; then
|
|
4273
|
-
_pass "#270 MEDIUM: an unresolvable FlowDefinition dies with the dedicated 'cannot be loaded' message, naming the flow id — NEVER the 'forged or corrupt' message"
|
|
4491
|
+
_pass "#270 MEDIUM: record-critique ignores poisoned navigation pointers and validates stamped claims against the exact session FlowDefinition"
|
|
4274
4492
|
else
|
|
4275
|
-
_fail "#270 MEDIUM:
|
|
4493
|
+
_fail "#270 MEDIUM REGRESSION: poisoned navigation pointers blocked or redirected an exact-session critique rebuild: $(cat "$TMPDIR_EVAL/unresolvable-critique.out" "$TMPDIR_EVAL/unresolvable-critique.err")"
|
|
4276
4494
|
fi
|
|
4277
4495
|
|
|
4278
4496
|
# ─── Mutation test (#270 HIGH reserved-prefix guard): temporarily disable normalizeCheck's ──────
|
|
@@ -4364,10 +4582,12 @@ flow_agents_node "$WRITER" ensure-session \
|
|
|
4364
4582
|
# not write trust.bundle yet) — a real, properly-stamped gate claim at pull-work-gate/selected-work,
|
|
4365
4583
|
# exactly the compose-layer pattern above, so this session has a normal, valid bundle to seed the
|
|
4366
4584
|
# mis-recorded claim alongside (never the sole content of the bundle).
|
|
4585
|
+
printf '%s\n' "# Pull Work Report" "" "Selected Work Item: local:${CORRECTION_SLUG}" > "$CORRECTION_DIR/${CORRECTION_SLUG}--pull-work.md"
|
|
4367
4586
|
flow_agents_node "$WRITER" record-gate-claim "$CORRECTION_DIR" \
|
|
4368
4587
|
--actor correction-actor \
|
|
4369
4588
|
--status pass \
|
|
4370
4589
|
--summary "Work item selected for correction-path session" \
|
|
4590
|
+
--evidence-ref-json '{"kind":"artifact","file":".kontourai/flow-agents/correction-270/correction-270--pull-work.md","summary":"Concrete pull-work selection report naming local:correction-270."}' \
|
|
4371
4591
|
--timestamp "2026-07-05T09:10:50Z" >"$TMPDIR_EVAL/correction-gate-seed.out" 2>"$TMPDIR_EVAL/correction-gate-seed.err"
|
|
4372
4592
|
|
|
4373
4593
|
if [[ ! -f "$CORRECTION_DIR/trust.bundle" ]]; then
|
|
@@ -4500,7 +4720,8 @@ flow_agents_node "$WRITER" ensure-session --artifact-root "$STAMPED_ROOT" --
|
|
|
4500
4720
|
|
|
4501
4721
|
# Real record-gate-claim call — a genuine, properly-stamped gate claim (metadata.gate_claim is
|
|
4502
4722
|
# stamped by buildTrustBundle itself, never hand-constructed).
|
|
4503
|
-
|
|
4723
|
+
printf '%s\n' "# Pull Work Report" "" "Selected Work Item: local:${STAMPED_SLUG}" > "$STAMPED_DIR/${STAMPED_SLUG}--pull-work.md"
|
|
4724
|
+
flow_agents_node "$WRITER" record-gate-claim "$STAMPED_DIR" --actor stamped-claim-actor --status pass --summary "Work item selected for stamped-claim supersession session" --evidence-ref-json '{"kind":"artifact","file":".kontourai/flow-agents/stamped-claim-270/stamped-claim-270--pull-work.md","summary":"Concrete pull-work selection report naming local:stamped-claim-270."}' --timestamp "2026-07-05T09:12:35Z" >"$TMPDIR_EVAL/stamped-claim-gate.out" 2>"$TMPDIR_EVAL/stamped-claim-gate.err"
|
|
4504
4725
|
|
|
4505
4726
|
if [[ ! -f "$STAMPED_DIR/trust.bundle" ]]; then
|
|
4506
4727
|
_fail "eval setup: record-gate-claim did not create trust.bundle for the stamped-claim session: $(cat "$TMPDIR_EVAL/stamped-claim-gate.out" "$TMPDIR_EVAL/stamped-claim-gate.err")"
|
|
@@ -4747,16 +4968,22 @@ NODEOF
|
|
|
4747
4968
|
cp "$MUTATION_SCRATCH/workflow-sidecar.mutated.js" "$DIST_SIDECAR"
|
|
4748
4969
|
# Copy the WHOLE root again (see the FORGED_ROOT/PRECLUSTER_ROOT comment above) — same
|
|
4749
4970
|
# current.json/current/<actor>.json resolution requirement applies here.
|
|
4750
|
-
|
|
4971
|
+
MUTATION_FORGED_PROJECT="$TMPDIR_EVAL/mutation-forged-project"
|
|
4972
|
+
MUTATION_FORGED_ROOT="$MUTATION_FORGED_PROJECT/.kontourai/flow-agents"
|
|
4973
|
+
mkdir -p "$MUTATION_FORGED_PROJECT/.kontourai"
|
|
4751
4974
|
cp -r "$FORGED_ROOT" "$MUTATION_FORGED_ROOT"
|
|
4752
4975
|
MUTATION_FORGED_DIR="$MUTATION_FORGED_ROOT/$COMPOSE_SLUG"
|
|
4753
|
-
|
|
4976
|
+
MUTATION_PRECLUSTER_PROJECT="$TMPDIR_EVAL/mutation-precluster-project"
|
|
4977
|
+
MUTATION_PRECLUSTER_ROOT="$MUTATION_PRECLUSTER_PROJECT/.kontourai/flow-agents"
|
|
4978
|
+
mkdir -p "$MUTATION_PRECLUSTER_PROJECT/.kontourai"
|
|
4754
4979
|
cp -r "$PRECLUSTER_ROOT" "$MUTATION_PRECLUSTER_ROOT"
|
|
4755
4980
|
MUTATION_PRECLUSTER_DIR="$MUTATION_PRECLUSTER_ROOT/$COMPOSE_SLUG"
|
|
4756
4981
|
|
|
4757
4982
|
if flow_agents_node "$WRITER" record-critique "$MUTATION_FORGED_DIR" \
|
|
4758
4983
|
--id mutation-forged-review --reviewer mutation-tester --verdict pass \
|
|
4759
4984
|
--summary "Mutation-test: forged-stamp guard disabled, must go red" \
|
|
4985
|
+
--artifact-ref "$(canonical_review_target "$MUTATION_FORGED_DIR")" \
|
|
4986
|
+
--lane-json "$CRITIQUE_LANE" \
|
|
4760
4987
|
--timestamp "2026-07-05T09:14:00Z" >"$TMPDIR_EVAL/mutation-forged.out" 2>"$TMPDIR_EVAL/mutation-forged.err"; then
|
|
4761
4988
|
_pass "mutation-test: with the stamp-mismatch guard neutered, the forged-stamp fixture now SUCCEEDS (eval correctly goes red without the guard, proving the guard is what the eval exercises)"
|
|
4762
4989
|
else
|
|
@@ -4766,6 +4993,8 @@ NODEOF
|
|
|
4766
4993
|
if flow_agents_node "$WRITER" record-critique "$MUTATION_PRECLUSTER_DIR" \
|
|
4767
4994
|
--id mutation-precluster-review --reviewer mutation-tester --verdict pass \
|
|
4768
4995
|
--summary "Mutation-test: pre-cluster-270 guard disabled, must go red" \
|
|
4996
|
+
--artifact-ref "$(canonical_review_target "$MUTATION_PRECLUSTER_DIR")" \
|
|
4997
|
+
--lane-json "$CRITIQUE_LANE" \
|
|
4769
4998
|
--timestamp "2026-07-05T09:14:30Z" >"$TMPDIR_EVAL/mutation-precluster.out" 2>"$TMPDIR_EVAL/mutation-precluster.err"; then
|
|
4770
4999
|
_pass "mutation-test: with the pre-cluster-270 unstamped guard neutered, the missing-stamp fixture now SUCCEEDS (eval correctly goes red without the guard)"
|
|
4771
5000
|
else
|
|
@@ -4778,12 +5007,16 @@ NODEOF
|
|
|
4778
5007
|
# Restore the real compiled guard immediately — never leave the mutated binary in place, and
|
|
4779
5008
|
# re-run BOTH negatives to confirm the restored binary rejects them again (guard is back).
|
|
4780
5009
|
cp "$MUTATION_SCRATCH/workflow-sidecar.orig.js" "$DIST_SIDECAR"
|
|
4781
|
-
|
|
5010
|
+
RESTORE_FORGED_PROJECT="$TMPDIR_EVAL/restore-check-forged-project"
|
|
5011
|
+
RESTORE_FORGED_ROOT="$RESTORE_FORGED_PROJECT/.kontourai/flow-agents"
|
|
5012
|
+
mkdir -p "$RESTORE_FORGED_PROJECT/.kontourai"
|
|
4782
5013
|
cp -r "$FORGED_ROOT" "$RESTORE_FORGED_ROOT"
|
|
4783
5014
|
RESTORE_FORGED_DIR="$RESTORE_FORGED_ROOT/$COMPOSE_SLUG"
|
|
4784
5015
|
if flow_agents_node "$WRITER" record-critique "$RESTORE_FORGED_DIR" \
|
|
4785
5016
|
--id restore-check-review --reviewer restore-check-tester --verdict pass \
|
|
4786
5017
|
--summary "Restore check: forged-stamp guard must be back after mutation-test cleanup" \
|
|
5018
|
+
--artifact-ref "$(canonical_review_target "$RESTORE_FORGED_DIR")" \
|
|
5019
|
+
--lane-json "$CRITIQUE_LANE" \
|
|
4787
5020
|
--timestamp "2026-07-05T09:15:00Z" >"$TMPDIR_EVAL/mutation-restore.out" 2>"$TMPDIR_EVAL/mutation-restore.err"; then
|
|
4788
5021
|
_fail "mutation-test cleanup REGRESSION: the forged-stamp guard did not come back after restoring the original compiled file"
|
|
4789
5022
|
else
|