@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
|
@@ -2242,12 +2242,12 @@ node - "$ROOT/scripts/hooks/stop-goal-fit.js" <<'NODEEOF' 2>"$TMPDIR_EVAL/hardbl
|
|
|
2242
2242
|
const fs = require('fs');
|
|
2243
2243
|
const file = process.argv[2];
|
|
2244
2244
|
let src = fs.readFileSync(file, 'utf8');
|
|
2245
|
-
const needle = "const HARD_BLOCK = /contradicts evidence\\.json|caught false-completion|evidence verdict:|evidence check .+ status:|critique status|critique open|required sidecar is missing|command-log integrity check FAILED|gate misconfiguration:|exit-code-laundered|NOT_VERIFIED \\(ambiguous\\)/;";
|
|
2245
|
+
const needle = "const HARD_BLOCK = /contradicts evidence\\.json|caught false-completion|evidence verdict:|evidence check .+ status:|critique status|critique open|required sidecar is missing|command-log integrity check FAILED|gate misconfiguration:|exit-code-laundered|NOT_VERIFIED \\(ambiguous\\)|canonical Flow (?:run remains active|state is unsafe or malformed)/;";
|
|
2246
2246
|
if (!src.includes(needle)) {
|
|
2247
2247
|
process.stderr.write('mutation: HARD_BLOCK NOT_VERIFIED (ambiguous) pattern not found — source pattern drifted, cannot mutation-test\n');
|
|
2248
2248
|
process.exit(1);
|
|
2249
2249
|
}
|
|
2250
|
-
const mutated = "const HARD_BLOCK = /contradicts evidence\\.json|caught false-completion|evidence verdict:|evidence check .+ status:|critique status|critique open|required sidecar is missing|command-log integrity check FAILED|gate misconfiguration:|exit-code-laundered/;";
|
|
2250
|
+
const mutated = "const HARD_BLOCK = /contradicts evidence\\.json|caught false-completion|evidence verdict:|evidence check .+ status:|critique status|critique open|required sidecar is missing|command-log integrity check FAILED|gate misconfiguration:|exit-code-laundered|canonical Flow (?:run remains active|state is unsafe or malformed)/;";
|
|
2251
2251
|
src = src.split(needle).join(mutated);
|
|
2252
2252
|
fs.writeFileSync(file, src);
|
|
2253
2253
|
NODEEOF
|
|
@@ -2712,6 +2712,64 @@ else
|
|
|
2712
2712
|
_fail "mutation-test cleanup re-check REGRESSION: restored stop-goal-fit.js no longer confirms a clean end-to-end pass for the dialect fixture: $(cat "$TMPDIR_EVAL/dialect-restore-e2e.out" "$TMPDIR_EVAL/dialect-restore-e2e.err")"
|
|
2713
2713
|
fi
|
|
2714
2714
|
|
|
2715
|
+
# Canonical Flow is authoritative for an active scoped session. Parent-directory
|
|
2716
|
+
# symlinks and malformed run state must therefore fail closed instead of being
|
|
2717
|
+
# silently treated as a missing optional run.
|
|
2718
|
+
CANONICAL_UNSAFE_REPO="$TMPDIR_EVAL/canonical-unsafe-repo"
|
|
2719
|
+
CANONICAL_UNSAFE_SESSION="$CANONICAL_UNSAFE_REPO/.kontourai/flow-agents/canonical-unsafe"
|
|
2720
|
+
mkdir -p "$CANONICAL_UNSAFE_SESSION"
|
|
2721
|
+
printf '# Test Repo\n' > "$CANONICAL_UNSAFE_REPO/AGENTS.md"
|
|
2722
|
+
cat > "$CANONICAL_UNSAFE_SESSION/canonical-unsafe--deliver.md" <<'MARKDOWN'
|
|
2723
|
+
# Canonical unsafe fixture
|
|
2724
|
+
|
|
2725
|
+
status: executing
|
|
2726
|
+
type: deliver
|
|
2727
|
+
MARKDOWN
|
|
2728
|
+
cat > "$CANONICAL_UNSAFE_SESSION/state.json" <<'JSON'
|
|
2729
|
+
{
|
|
2730
|
+
"task_slug": "canonical-unsafe",
|
|
2731
|
+
"status": "executing",
|
|
2732
|
+
"phase": "execution",
|
|
2733
|
+
"flow_run": { "status": "active", "current_step": "verify" }
|
|
2734
|
+
}
|
|
2735
|
+
JSON
|
|
2736
|
+
cat > "$CANONICAL_UNSAFE_REPO/.kontourai/flow-agents/current.json" <<'JSON'
|
|
2737
|
+
{ "active_slug": "canonical-unsafe" }
|
|
2738
|
+
JSON
|
|
2739
|
+
CANONICAL_OUTSIDE="$TMPDIR_EVAL/canonical-outside"
|
|
2740
|
+
mkdir -p "$CANONICAL_OUTSIDE"
|
|
2741
|
+
ln -s "$CANONICAL_OUTSIDE" "$CANONICAL_UNSAFE_REPO/.kontourai/flow"
|
|
2742
|
+
if FLOW_AGENTS_GOAL_FIT_STRICT=true node "$ROOT/scripts/hooks/stop-goal-fit.js" >"$TMPDIR_EVAL/canonical-symlink.out" 2>"$TMPDIR_EVAL/canonical-symlink.err" <<JSON
|
|
2743
|
+
{"hook_event_name":"Stop","cwd":"$CANONICAL_UNSAFE_REPO"}
|
|
2744
|
+
JSON
|
|
2745
|
+
then
|
|
2746
|
+
_fail "strict goal-fit hook allowed an active scoped session with a symlinked canonical Flow parent"
|
|
2747
|
+
elif [[ "$?" -eq 2 ]] && grep -q 'canonical Flow state is unsafe or malformed' "$TMPDIR_EVAL/canonical-symlink.err"; then
|
|
2748
|
+
_pass "strict goal-fit hook rejects symlinked canonical Flow parent components for an active scoped session"
|
|
2749
|
+
else
|
|
2750
|
+
_fail "strict goal-fit hook did not report the unsafe canonical Flow parent: $(cat "$TMPDIR_EVAL/canonical-symlink.err")"
|
|
2751
|
+
fi
|
|
2752
|
+
|
|
2753
|
+
rm "$CANONICAL_UNSAFE_REPO/.kontourai/flow"
|
|
2754
|
+
mkdir -p "$CANONICAL_UNSAFE_REPO/.kontourai/flow/runs/canonical-unsafe"
|
|
2755
|
+
printf 'not-json\n' > "$CANONICAL_UNSAFE_REPO/.kontourai/flow/runs/canonical-unsafe/state.json"
|
|
2756
|
+
if FLOW_AGENTS_GOAL_FIT_STRICT=true node "$ROOT/scripts/hooks/stop-goal-fit.js" >"$TMPDIR_EVAL/canonical-malformed.out" 2>"$TMPDIR_EVAL/canonical-malformed.err" <<JSON
|
|
2757
|
+
{"hook_event_name":"Stop","cwd":"$CANONICAL_UNSAFE_REPO"}
|
|
2758
|
+
JSON
|
|
2759
|
+
then
|
|
2760
|
+
_fail "strict goal-fit hook allowed an active scoped session with malformed canonical Flow state"
|
|
2761
|
+
elif [[ "$?" -eq 2 ]] && grep -q 'canonical Flow state is unsafe or malformed' "$TMPDIR_EVAL/canonical-malformed.err"; then
|
|
2762
|
+
_pass "strict goal-fit hook fails closed for malformed canonical Flow state of an active scoped session"
|
|
2763
|
+
else
|
|
2764
|
+
_fail "strict goal-fit hook did not report malformed canonical Flow state: $(cat "$TMPDIR_EVAL/canonical-malformed.err")"
|
|
2765
|
+
fi
|
|
2766
|
+
|
|
2767
|
+
if cmp -s "$ROOT/scripts/hooks/stop-goal-fit.js" "$ROOT/context/scripts/hooks/stop-goal-fit.js"; then
|
|
2768
|
+
_pass "canonical Stop hook source and shipped context mirror remain byte-identical"
|
|
2769
|
+
else
|
|
2770
|
+
_fail "canonical Stop hook source and shipped context mirror diverged"
|
|
2771
|
+
fi
|
|
2772
|
+
|
|
2715
2773
|
|
|
2716
2774
|
if [[ "$errors" -eq 0 ]]; then
|
|
2717
2775
|
echo "Goal Fit hook integration passed."
|
|
@@ -22,6 +22,10 @@ set -euo pipefail
|
|
|
22
22
|
|
|
23
23
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
24
24
|
TMPDIR_EVAL="$(mktemp -d /tmp/install-merge.XXXXXX)"
|
|
25
|
+
export HOME="$TMPDIR_EVAL/hermetic-home"
|
|
26
|
+
export FLOW_AGENTS_SKILLS_DIR="$TMPDIR_EVAL/hermetic-universal/skills"
|
|
27
|
+
mkdir -p "$HOME/.agents" "$FLOW_AGENTS_SKILLS_DIR"
|
|
28
|
+
printf 'installer tests must not replace this file\n' > "$HOME/.agents/ambient-sentinel"
|
|
25
29
|
pass=0
|
|
26
30
|
fail=0
|
|
27
31
|
|
|
@@ -1138,7 +1142,8 @@ echo ""
|
|
|
1138
1142
|
echo "--- CH4: codex-home preserves user config, profiles, hooks, local kit state, and user skills ---"
|
|
1139
1143
|
|
|
1140
1144
|
CH4_DEST="$TMPDIR_EVAL/codex-home-ch4"
|
|
1141
|
-
|
|
1145
|
+
CH4_SKILLS="$TMPDIR_EVAL/codex-home-ch4-universal-skills"
|
|
1146
|
+
mkdir -p "$CH4_DEST/kits/local/repositories/user-kit" "$CH4_SKILLS/user-owned-skill" "$CH4_DEST/ag""ents"
|
|
1142
1147
|
|
|
1143
1148
|
CH4_GENERIC_DIRS=(agent-cards build context docs evals integrations packaging powers prompts schemas scripts kits)
|
|
1144
1149
|
for CH4_DIR in "${CH4_GENERIC_DIRS[@]}"; do
|
|
@@ -1197,14 +1202,14 @@ JSON
|
|
|
1197
1202
|
cat > "$CH4_DEST/kits/local/repositories/user-kit/kit.json" << 'JSON'
|
|
1198
1203
|
{"id":"user-kit","name":"User Kit"}
|
|
1199
1204
|
JSON
|
|
1200
|
-
cat > "$
|
|
1205
|
+
cat > "$CH4_SKILLS/user-owned-skill/SKILL.md" << 'EOF_SKILL'
|
|
1201
1206
|
# User Owned Skill
|
|
1202
1207
|
EOF_SKILL
|
|
1203
1208
|
cat > "$CH4_DEST/ag""ents/user-owned-agent.toml" << 'EOF_AGENT'
|
|
1204
1209
|
name = "user-owned-agent"
|
|
1205
1210
|
EOF_AGENT
|
|
1206
1211
|
|
|
1207
|
-
CODEX_REAL_HOME="$TMPDIR_EVAL/fake-real-codex" bash "$ROOT_DIR/scripts/install-codex-home.sh" "$CH4_DEST" >/dev/null 2>&1
|
|
1212
|
+
CODEX_REAL_HOME="$TMPDIR_EVAL/fake-real-codex" FLOW_AGENTS_SKILLS_DIR="$CH4_SKILLS" bash "$ROOT_DIR/scripts/install-codex-home.sh" "$CH4_DEST" >/dev/null 2>&1
|
|
1208
1213
|
|
|
1209
1214
|
if grep -q 'user-model' "$CH4_DEST/config.toml" \
|
|
1210
1215
|
&& grep -q 'user-profile-model' "$CH4_DEST/custom.config.toml" \
|
|
@@ -1243,10 +1248,10 @@ else
|
|
|
1243
1248
|
_fail "CH4: kits/local registry or repository was removed"
|
|
1244
1249
|
fi
|
|
1245
1250
|
|
|
1246
|
-
if [[ -f "$
|
|
1247
|
-
_pass "CH4: root, Builder Kit workflow, and user-owned skills coexist in
|
|
1251
|
+
if [[ -f "$CH4_SKILLS/search-first/SKILL.md" && -f "$CH4_SKILLS/plan-work/SKILL.md" && -f "$CH4_SKILLS/user-owned-skill/SKILL.md" ]]; then
|
|
1252
|
+
_pass "CH4: root, Builder Kit workflow, and user-owned skills coexist in universal Codex skills"
|
|
1248
1253
|
else
|
|
1249
|
-
_fail "CH4: root skill, Builder Kit workflow skill, or user-owned skill missing from
|
|
1254
|
+
_fail "CH4: root skill, Builder Kit workflow skill, or user-owned skill missing from universal Codex skills"
|
|
1250
1255
|
fi
|
|
1251
1256
|
|
|
1252
1257
|
if [[ -f "$CH4_DEST/scripts/install-merge.js" && -f "$CH4_DEST/build/src/cli/kit.js" && -f "$CH4_DEST/ag""ents/tool-worker.toml" && -f "$CH4_DEST/ag""ents/user-owned-agent.toml" && -f "$CH4_DEST/hooks.json" ]] \
|
|
@@ -1272,7 +1277,7 @@ else
|
|
|
1272
1277
|
_fail "CH4: installed scripts/kit.js could not run with installed build bundle"
|
|
1273
1278
|
fi
|
|
1274
1279
|
|
|
1275
|
-
CODEX_REAL_HOME="$TMPDIR_EVAL/fake-real-codex" bash "$ROOT_DIR/scripts/install-codex-home.sh" "$CH4_DEST" >/dev/null 2>&1
|
|
1280
|
+
CODEX_REAL_HOME="$TMPDIR_EVAL/fake-real-codex" FLOW_AGENTS_SKILLS_DIR="$CH4_SKILLS" bash "$ROOT_DIR/scripts/install-codex-home.sh" "$CH4_DEST" >/dev/null 2>&1
|
|
1276
1281
|
CH4_GENERIC_PRESERVED=1
|
|
1277
1282
|
for CH4_DIR in "${CH4_GENERIC_DIRS[@]}"; do
|
|
1278
1283
|
[[ "$(cat "$CH4_DEST/$CH4_DIR/user-owned.txt" 2>/dev/null)" == "user-owned-$CH4_DIR" ]] || CH4_GENERIC_PRESERVED=0
|
|
@@ -1288,7 +1293,7 @@ echo ""
|
|
|
1288
1293
|
# ─── codex-home: CH5: destination symlink containment ───────────────────────
|
|
1289
1294
|
echo "--- CH5: codex-home refuses managed destination symlinks ---"
|
|
1290
1295
|
|
|
1291
|
-
for CH5_REL in scripts kits
|
|
1296
|
+
for CH5_REL in scripts kits hooks.json; do
|
|
1292
1297
|
CH5_DEST="$TMPDIR_EVAL/codex-home-ch5-${CH5_REL//\//-}"
|
|
1293
1298
|
CH5_OUTSIDE="$TMPDIR_EVAL/codex-home-ch5-outside-${CH5_REL//\//-}"
|
|
1294
1299
|
mkdir -p "$CH5_DEST" "$CH5_OUTSIDE"
|
|
@@ -1680,6 +1685,11 @@ echo ""
|
|
|
1680
1685
|
|
|
1681
1686
|
echo ""
|
|
1682
1687
|
echo "==========================="
|
|
1688
|
+
if [[ "$(cat "$HOME/.agents/ambient-sentinel" 2>/dev/null)" == "installer tests must not replace this file" ]]; then
|
|
1689
|
+
_pass "dedicated Codex installer calls remain inside hermetic universal roots"
|
|
1690
|
+
else
|
|
1691
|
+
_fail "dedicated Codex installer calls mutated the isolated default-home sentinel"
|
|
1692
|
+
fi
|
|
1683
1693
|
total=$((pass + fail))
|
|
1684
1694
|
echo "Results: ${pass}/${total} passed, ${fail} failed"
|
|
1685
1695
|
[[ "$fail" -gt 0 ]] && exit 1
|
|
@@ -292,23 +292,20 @@ else
|
|
|
292
292
|
fi
|
|
293
293
|
|
|
294
294
|
# ─── G. Static skill-text assertions (AC2) ──────────────────────────────────
|
|
295
|
-
echo "--- G.
|
|
296
|
-
|
|
297
|
-
require_text "$PULL" '
|
|
298
|
-
require_text "$PULL" '
|
|
299
|
-
require_text "$PULL" '
|
|
300
|
-
require_text "$PULL" '
|
|
301
|
-
require_text "$PULL" '
|
|
302
|
-
require_text "$PULL" '
|
|
303
|
-
require_text "$PULL" '
|
|
304
|
-
require_text "$PULL" '
|
|
305
|
-
require_text "$PULL" '
|
|
306
|
-
require_text "$PULL" '
|
|
307
|
-
require_text "$PULL" '
|
|
308
|
-
require_text "$PULL" '
|
|
309
|
-
require_text "$PULL" 'record the verdict for transparency \(.\{verdict_reason, winner_actor: self_actor, conceded: false\}.\) in .post_claim_conflict. and proceed normally; do not release' "pull-work's winner branch records the verdict for transparency and proceeds without releasing (AC2)"
|
|
310
|
-
require_text "$PULL" 'closes the .detected but advisory-only. gap ADR 0012 §4 names for THIS session.s own double-hold' "pull-work's honesty note states the verdict+release loop closes the detected-but-advisory-only gap for this session's own double-hold (AC2)"
|
|
311
|
-
require_text "$PULL" 'still does not provide true mutual exclusion across the read-then-write race window itself' "pull-work's honesty note distinguishes the new convergence guarantee from the unchanged read-then-write race residual (AC2)"
|
|
295
|
+
echo "--- G. Provider-neutral pull-work conflict contract assertions ---"
|
|
296
|
+
|
|
297
|
+
require_text "$PULL" 'deterministic conflict arbitration' "pull-work uses provider conflict arbitration"
|
|
298
|
+
require_text "$PULL" 'same pinned caller identity, subject, and observation' "pull-work reuses one conflict snapshot"
|
|
299
|
+
require_text "$PULL" 'Prefer the earlier claim' "pull-work defines deterministic winner precedence"
|
|
300
|
+
require_text "$PULL" 'exact timestamp tie by ascending' "pull-work defines deterministic tie handling"
|
|
301
|
+
require_text "$PULL" 'same winner from the same state' "pull-work requires actor-independent verdicts"
|
|
302
|
+
require_text "$PULL" 'If the caller loses' "pull-work defines loser behavior"
|
|
303
|
+
require_text "$PULL" 'release or concede its claim immediately' "pull-work makes the loser concede"
|
|
304
|
+
require_text "$PULL" 'conceded: true' "pull-work records loser concession"
|
|
305
|
+
require_text "$PULL" 'exclude the contested subject' "pull-work excludes the lost subject before reselection"
|
|
306
|
+
require_text "$PULL" 'If the caller wins' "pull-work defines winner behavior"
|
|
307
|
+
require_text "$PULL" 'conceded: false' "pull-work records winner transparency"
|
|
308
|
+
require_text "$PULL" 'underlying read-then-write race' "pull-work distinguishes convergence from mutual exclusion"
|
|
312
309
|
|
|
313
310
|
# ─── H. Hostile-actor injection: winner.actor sanitized in --json and text (F5) ─────
|
|
314
311
|
echo "--- H. Hostile-actor verdict sanitization (F5) ---"
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
# 4. record-gate-claim at pull-work step produces builder.pull-work.selected claim (status=verified).
|
|
9
9
|
# 5. A TAMPERED bundle (stored verified, evidence fail) at pull-work step BLOCKS (exit 2)
|
|
10
10
|
# with the tamper warning naming the declared claimType.
|
|
11
|
-
# 6. A CLEAN
|
|
11
|
+
# 6. A CLEAN public Builder bundle is not reported as false completion;
|
|
12
12
|
# its still-active canonical Flow run remains blocked from stopping.
|
|
13
13
|
#
|
|
14
14
|
# Deterministic, no model spend, self-cleaning.
|
|
@@ -162,10 +162,14 @@ flow_agents_node "workflow-sidecar" init-plan "$CLAIM_ROOT/gate-claim/gate-claim
|
|
|
162
162
|
--source-request "Test" --summary "Testing" \
|
|
163
163
|
--timestamp "2026-06-26T00:00:00Z" >/dev/null 2>&1
|
|
164
164
|
|
|
165
|
+
CLAIM_ARTIFACT="$CLAIM_ROOT/gate-claim/gate-claim--pull-work.md"
|
|
166
|
+
printf '# Pull Work\n\nSelected issue #177 for implementation.\n' > "$CLAIM_ARTIFACT"
|
|
167
|
+
|
|
165
168
|
if flow_agents_node "workflow-sidecar" record-gate-claim "$CLAIM_ROOT/gate-claim" \
|
|
166
169
|
--status pass \
|
|
167
170
|
--summary "Selected issue #177 for implementation." \
|
|
168
171
|
--expectation selected-work \
|
|
172
|
+
--evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$CLAIM_ARTIFACT\",\"summary\":\"Declared durable pull-work artifact for selected-work.\"}" \
|
|
169
173
|
--timestamp "2026-06-26T00:01:00Z" >/dev/null 2>&1; then
|
|
170
174
|
_pass "record-gate-claim exits 0 at pull-work step"
|
|
171
175
|
else
|
|
@@ -188,9 +192,18 @@ node -e "
|
|
|
188
192
|
console.error('expected status=verified, got', target.status);
|
|
189
193
|
process.exit(1);
|
|
190
194
|
}
|
|
195
|
+
const expectedArtifact = '.kontourai/flow-agents/gate-claim/gate-claim--pull-work.md';
|
|
196
|
+
if (!fs.existsSync('$CLAIM_ARTIFACT')) {
|
|
197
|
+
console.error('missing declared durable selected-work artifact:', '$CLAIM_ARTIFACT');
|
|
198
|
+
process.exit(1);
|
|
199
|
+
}
|
|
200
|
+
if (!target.metadata?.artifact_refs?.some(ref => ref.kind === 'artifact' && ref.file === expectedArtifact)) {
|
|
201
|
+
console.error('selected-work claim does not cite declared artifact:', JSON.stringify(target.metadata?.artifact_refs));
|
|
202
|
+
process.exit(1);
|
|
203
|
+
}
|
|
191
204
|
" 2>/dev/null \
|
|
192
|
-
&& _pass "bundle contains builder.pull-work.selected with
|
|
193
|
-
|| _fail "bundle missing or
|
|
205
|
+
&& _pass "bundle contains builder.pull-work.selected with declared durable artifact evidence" \
|
|
206
|
+
|| _fail "bundle missing selected-work claim or declared durable artifact evidence"
|
|
194
207
|
|
|
195
208
|
echo ""
|
|
196
209
|
echo "=== 4b. composed publish-learn gate claim emits builder.pr-open.pull-request ==="
|
|
@@ -215,10 +228,14 @@ flow_agents_node "workflow-sidecar" advance-state "$COMPOSED_ROOT/composed-gate-
|
|
|
215
228
|
--flow-definition builder.build \
|
|
216
229
|
--timestamp "2026-06-26T00:00:30Z" >/dev/null 2>&1
|
|
217
230
|
|
|
231
|
+
COMPOSED_ARTIFACT="$COMPOSED_ROOT/composed-gate-claim/release.json"
|
|
232
|
+
printf '{"schema_version":"1.0","task_slug":"composed-gate-claim","status":"pr_open"}\n' > "$COMPOSED_ARTIFACT"
|
|
233
|
+
|
|
218
234
|
if flow_agents_node "workflow-sidecar" record-gate-claim "$COMPOSED_ROOT/composed-gate-claim" \
|
|
219
235
|
--status pass \
|
|
220
236
|
--summary "PR opened with verification evidence." \
|
|
221
237
|
--expectation pull-request-opened \
|
|
238
|
+
--evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$COMPOSED_ARTIFACT\",\"summary\":\"Declared durable release artifact for pull-request-opened.\"}" \
|
|
222
239
|
--timestamp "2026-06-26T00:01:00Z" >/dev/null 2>&1; then
|
|
223
240
|
_pass "record-gate-claim exits 0 at composed pr-open step"
|
|
224
241
|
else
|
|
@@ -244,9 +261,18 @@ node -e "
|
|
|
244
261
|
console.error('expected status=verified, got', target.status);
|
|
245
262
|
process.exit(1);
|
|
246
263
|
}
|
|
264
|
+
const expectedArtifact = '.kontourai/flow-agents/composed-gate-claim/release.json';
|
|
265
|
+
if (!fs.existsSync('$COMPOSED_ARTIFACT')) {
|
|
266
|
+
console.error('missing declared durable pr-open artifact:', '$COMPOSED_ARTIFACT');
|
|
267
|
+
process.exit(1);
|
|
268
|
+
}
|
|
269
|
+
if (!target.metadata?.artifact_refs?.some(ref => ref.kind === 'artifact' && ref.file === expectedArtifact)) {
|
|
270
|
+
console.error('pr-open claim does not cite declared artifact:', JSON.stringify(target.metadata?.artifact_refs));
|
|
271
|
+
process.exit(1);
|
|
272
|
+
}
|
|
247
273
|
" 2>/dev/null \
|
|
248
|
-
&& _pass "composed bundle contains builder.pr-open.pull-request with
|
|
249
|
-
|| _fail "composed bundle missing
|
|
274
|
+
&& _pass "composed bundle contains builder.pr-open.pull-request with declared durable artifact evidence" \
|
|
275
|
+
|| _fail "composed bundle missing pr-open claim or declared durable artifact evidence"
|
|
250
276
|
|
|
251
277
|
# ─── Tamper-blocks: stored verified + evidence fail → BLOCK (exit 2) ─────────
|
|
252
278
|
echo ""
|
|
@@ -355,59 +381,58 @@ fi
|
|
|
355
381
|
|
|
356
382
|
# ─── Clean gate-claim: no false completion, active Flow still blocks ─────────
|
|
357
383
|
echo ""
|
|
358
|
-
echo "=== 6. CLEAN
|
|
384
|
+
echo "=== 6. CLEAN public Builder evidence remains governed by active canonical Flow ==="
|
|
359
385
|
|
|
360
386
|
C_DIR="$TMP/clean-test"
|
|
387
|
+
CLEAN_SLUG="provider-clean"
|
|
361
388
|
mkdir -p "$C_DIR"
|
|
362
389
|
printf '# Repo\n' > "$C_DIR/AGENTS.md"
|
|
390
|
+
mkdir -p "$C_DIR/.kontourai/flow-agents/$CLEAN_SLUG"
|
|
391
|
+
CLEAN_ARTIFACT="$C_DIR/.kontourai/flow-agents/$CLEAN_SLUG/$CLEAN_SLUG--pull-work.md"
|
|
392
|
+
printf 'Selected Work Item: provider:clean\n' > "$CLEAN_ARTIFACT"
|
|
363
393
|
|
|
364
|
-
|
|
394
|
+
if ! FLOW_AGENTS_ACTOR=clean-fixture-actor node "$ROOT/build/src/cli.js" workflow start \
|
|
365
395
|
--artifact-root "$C_DIR/.kontourai/flow-agents" \
|
|
366
|
-
--
|
|
396
|
+
--flow builder.build \
|
|
397
|
+
--work-item provider:clean \
|
|
398
|
+
--assignment-provider local-file \
|
|
367
399
|
--title "Clean Test" \
|
|
368
|
-
--summary "Testing clean gate claim."
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
--timestamp "2026-06-26T00:00:00Z" >/dev/null 2>&1
|
|
400
|
+
--summary "Testing clean gate claim." >"$TMP/clean-start.out" 2>&1; then
|
|
401
|
+
_fail "public clean fixture failed to start: $(cat "$TMP/clean-start.out")"
|
|
402
|
+
fi
|
|
372
403
|
|
|
373
|
-
flow_agents_node "workflow-sidecar" init-plan "$C_DIR/.kontourai/flow-agents
|
|
404
|
+
flow_agents_node "workflow-sidecar" init-plan "$C_DIR/.kontourai/flow-agents/$CLEAN_SLUG/$CLEAN_SLUG--deliver.md" \
|
|
374
405
|
--source-request "Test" --summary "Testing" \
|
|
375
406
|
--timestamp "2026-06-26T00:00:00Z" >/dev/null 2>&1
|
|
376
407
|
|
|
377
|
-
flow_agents_node "workflow-sidecar" advance-state "$C_DIR/.kontourai/flow-agents/clean" \
|
|
378
|
-
--status in_progress \
|
|
379
|
-
--phase pickup \
|
|
380
|
-
--summary "In progress." \
|
|
381
|
-
--next-action "done" \
|
|
382
|
-
--flow-definition builder.build \
|
|
383
|
-
--timestamp "2026-06-26T00:00:30Z" >/dev/null 2>&1
|
|
384
|
-
|
|
385
408
|
# Fix next_action so it reads as "done" for the gate
|
|
386
409
|
node -e "
|
|
387
410
|
const fs = require('fs');
|
|
388
|
-
const f = '$C_DIR/.kontourai/flow-agents/
|
|
411
|
+
const f = '$C_DIR/.kontourai/flow-agents/$CLEAN_SLUG/state.json';
|
|
389
412
|
const s = JSON.parse(fs.readFileSync(f, 'utf8'));
|
|
390
413
|
s.next_action = { status: 'done', summary: 'Work complete.' };
|
|
391
414
|
s.status = 'verified';
|
|
415
|
+
delete s.flow_run;
|
|
392
416
|
fs.writeFileSync(f, JSON.stringify(s, null, 2) + '\n');
|
|
393
417
|
" 2>/dev/null
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
418
|
+
rm -f "$C_DIR/.kontourai/flow-agents/$CLEAN_SLUG/$CLEAN_SLUG--deliver.md"
|
|
419
|
+
|
|
420
|
+
clean_out=""
|
|
421
|
+
clean_exit=0
|
|
422
|
+
for attempt in 1 2; do
|
|
423
|
+
set +e
|
|
424
|
+
attempt_out="$(FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_MAX_BLOCKS=2 FLOW_AGENTS_GOAL_FIT_BACKSTOP=skip \
|
|
425
|
+
node "$GATE" 2>&1 <<< "{\"hook_event_name\":\"Stop\",\"cwd\":\"$C_DIR\"}")"
|
|
426
|
+
attempt_exit="$?"
|
|
427
|
+
set -e
|
|
428
|
+
clean_out="$clean_out$attempt_out"
|
|
429
|
+
if [ "$attempt_exit" -ne 2 ]; then clean_exit="$attempt_exit"; fi
|
|
430
|
+
done
|
|
431
|
+
|
|
432
|
+
if [ "$clean_exit" -eq 0 ] && echo "$clean_out" | grep -q 'canonical Flow run remains active at step design-probe'; then
|
|
433
|
+
_pass "canonical Flow blocks repeated Stop after the sidecar projection and Markdown are removed"
|
|
409
434
|
else
|
|
410
|
-
_fail "
|
|
435
|
+
_fail "canonical Flow could be hidden or auto-released after sidecar rewrite (exit $clean_exit): $clean_out"
|
|
411
436
|
fi
|
|
412
437
|
|
|
413
438
|
if echo "$clean_out" | grep -q "caught false-completion"; then
|