@kontourai/flow-agents 3.4.3 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +4 -0
- package/CHANGELOG.md +15 -0
- package/build/src/builder-flow-run-adapter.d.ts +10 -1
- package/build/src/builder-flow-run-adapter.js +29 -1
- package/build/src/builder-flow-runtime.d.ts +18 -0
- package/build/src/builder-flow-runtime.js +205 -13
- package/build/src/builder-lifecycle-authority.d.ts +35 -0
- package/build/src/builder-lifecycle-authority.js +219 -0
- package/build/src/cli/assignment-provider.d.ts +13 -0
- package/build/src/cli/assignment-provider.js +120 -62
- package/build/src/cli/builder-run.js +46 -5
- package/build/src/cli/workflow-artifact-cleanup-audit.js +3 -0
- package/build/src/cli/workflow-sidecar.d.ts +3 -0
- package/build/src/cli/workflow-sidecar.js +140 -30
- package/build/src/cli/workflow.d.ts +2 -0
- package/build/src/cli/workflow.js +521 -0
- package/build/src/cli.js +2 -0
- package/build/src/index.d.ts +4 -0
- package/build/src/index.js +2 -0
- package/build/src/lib/flow-resolver.js +7 -2
- package/build/src/lib/package-version.d.ts +2 -0
- package/build/src/lib/package-version.js +13 -0
- package/build/src/lib/pinned-cli-command.d.ts +6 -0
- package/build/src/lib/pinned-cli-command.js +21 -0
- package/context/contracts/artifact-contract.md +1 -1
- package/context/contracts/assignment-provider-contract.md +5 -2
- package/context/scripts/hooks/config-protection.js +8 -1
- package/context/scripts/hooks/lib/config-protection-remedies.js +3 -0
- package/context/scripts/hooks/stop-goal-fit.js +1 -1
- package/docs/context-map.md +2 -0
- package/docs/public-workflow-cli.md +63 -0
- package/docs/spec/builder-flow-runtime.md +49 -5
- package/docs/workflow-usage-guide.md +5 -0
- package/evals/ci/run-baseline.sh +2 -0
- package/evals/integration/test_assignment_provider_local_file.sh +54 -0
- package/evals/integration/test_builder_entry_enforcement.sh +241 -24
- package/evals/integration/test_bundle_install.sh +97 -0
- package/evals/integration/test_current_json_per_actor.sh +1 -0
- package/evals/integration/test_dual_emit_flow_step.sh +2 -0
- package/evals/integration/test_flowdef_session_activation.sh +6 -3
- package/evals/integration/test_goal_fit_escape_hatch.sh +3 -3
- package/evals/integration/test_phase_map_and_gate_claim.sh +4 -0
- package/evals/integration/test_public_workflow_cli.sh +259 -0
- package/evals/integration/test_workflow_sidecar_writer.sh +1 -0
- package/package.json +2 -2
- package/schemas/builder-lifecycle-authorization.schema.json +57 -0
- package/schemas/lifecycle-authority-keys.schema.json +25 -0
- package/schemas/workflow-state.schema.json +1 -1
- package/scripts/hooks/config-protection.js +8 -1
- package/scripts/hooks/lib/config-protection-remedies.js +3 -0
- package/scripts/hooks/stop-goal-fit.js +1 -1
- package/src/builder-flow-run-adapter.ts +47 -0
- package/src/builder-flow-runtime.ts +216 -4
- package/src/builder-lifecycle-authority.ts +218 -0
- package/src/cli/assignment-provider.ts +84 -20
- package/src/cli/builder-flow-runtime.test.mjs +404 -1
- package/src/cli/builder-run.ts +56 -5
- package/src/cli/workflow-artifact-cleanup-audit.ts +3 -0
- package/src/cli/workflow-sidecar.ts +138 -31
- package/src/cli/workflow.ts +471 -0
- package/src/cli.ts +2 -0
- package/src/index.ts +14 -0
- package/src/lib/flow-resolver.ts +6 -2
- package/src/lib/package-version.ts +15 -0
- package/src/lib/pinned-cli-command.ts +23 -0
|
@@ -50,6 +50,48 @@ else
|
|
|
50
50
|
fail "symlinked Builder root wrote externally or returned the wrong diagnostic: $(cat "$TMP/symlink-root.out")"
|
|
51
51
|
fi
|
|
52
52
|
|
|
53
|
+
SESSION_SYMLINK_PROJECT="$TMP/session-symlink-project"
|
|
54
|
+
SESSION_SYMLINK_ROOT="$SESSION_SYMLINK_PROJECT/.kontourai/flow-agents"
|
|
55
|
+
SESSION_SYMLINK_EXTERNAL="$TMP/session-symlink-external"
|
|
56
|
+
mkdir -p "$SESSION_SYMLINK_ROOT" "$SESSION_SYMLINK_EXTERNAL"
|
|
57
|
+
ln -s "$SESSION_SYMLINK_EXTERNAL" "$SESSION_SYMLINK_ROOT/session-symlink"
|
|
58
|
+
if flow_agents_node "$WRITER" ensure-session \
|
|
59
|
+
--artifact-root "$SESSION_SYMLINK_ROOT" \
|
|
60
|
+
--task-slug session-symlink \
|
|
61
|
+
--actor builder-entry-session-symlink \
|
|
62
|
+
--title "Session symlink" \
|
|
63
|
+
--summary "Session state must not escape the artifact root." \
|
|
64
|
+
--flow-id builder.build >"$TMP/session-symlink.out" 2>&1; then
|
|
65
|
+
fail "symlinked session directory should be rejected"
|
|
66
|
+
elif [[ -z "$(find "$SESSION_SYMLINK_EXTERNAL" -mindepth 1 -print -quit)" ]] \
|
|
67
|
+
&& grep -q 'session directory must be a real directory under the artifact root' "$TMP/session-symlink.out"; then
|
|
68
|
+
pass "symlinked session directory is rejected before external reads or writes"
|
|
69
|
+
else
|
|
70
|
+
fail "symlinked session directory escaped or returned the wrong diagnostic: $(cat "$TMP/session-symlink.out")"
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
NESTED_PROJECT="$TMP/nested-symlink-project"
|
|
74
|
+
NESTED_ROOT="$NESTED_PROJECT/.kontourai/flow-agents"
|
|
75
|
+
NESTED_EXTERNAL="$TMP/nested-symlink-external.json"
|
|
76
|
+
mkdir -p "$NESTED_ROOT/assignment"
|
|
77
|
+
printf 'external must survive\n' >"$NESTED_EXTERNAL"
|
|
78
|
+
ln -s "$NESTED_EXTERNAL" "$NESTED_ROOT/assignment/nested-symlink.json"
|
|
79
|
+
if flow_agents_node "$WRITER" ensure-session \
|
|
80
|
+
--artifact-root "$NESTED_ROOT" \
|
|
81
|
+
--task-slug nested-symlink \
|
|
82
|
+
--actor builder-entry-nested-symlink \
|
|
83
|
+
--title "Nested assignment symlink" \
|
|
84
|
+
--summary "Assignment evidence must stay inside the product root." \
|
|
85
|
+
--flow-id builder.build >"$TMP/nested-symlink.out" 2>&1; then
|
|
86
|
+
fail "symlinked assignment record should be rejected"
|
|
87
|
+
elif [[ "$(cat "$NESTED_EXTERNAL")" == "external must survive" ]] \
|
|
88
|
+
&& [[ ! -e "$NESTED_ROOT/nested-symlink" ]] \
|
|
89
|
+
&& grep -q 'assignment record must be a regular file, not a symlink' "$TMP/nested-symlink.out"; then
|
|
90
|
+
pass "nested assignment symlink is rejected before external write or trust evidence"
|
|
91
|
+
else
|
|
92
|
+
fail "nested assignment symlink escaped or returned the wrong diagnostic: $(cat "$TMP/nested-symlink.out")"
|
|
93
|
+
fi
|
|
94
|
+
|
|
53
95
|
RACE_PROJECT="$TMP/race-project"
|
|
54
96
|
RACE_ROOT="$RACE_PROJECT/.kontourai/flow-agents"
|
|
55
97
|
RACE_MOVED="$RACE_PROJECT/.kontourai/flow-agents-acquired"
|
|
@@ -146,6 +188,7 @@ LOCAL_ROOT="$TMP/local/.kontourai/flow-agents"
|
|
|
146
188
|
if flow_agents_node "$WRITER" ensure-session \
|
|
147
189
|
--artifact-root "$LOCAL_ROOT" \
|
|
148
190
|
--task-slug local-request \
|
|
191
|
+
--actor builder-entry-local \
|
|
149
192
|
--title "Local request" \
|
|
150
193
|
--summary "Providerless work still needs an anchor." \
|
|
151
194
|
--flow-id builder.build \
|
|
@@ -158,19 +201,24 @@ const current = JSON.parse(fs.readFileSync(path.join(root, 'current.json'), 'utf
|
|
|
158
201
|
const state = JSON.parse(fs.readFileSync(path.join(root, 'local-request', 'state.json'), 'utf8'));
|
|
159
202
|
const workItem = JSON.parse(fs.readFileSync(path.join(root, 'local-request', 'work-item.json'), 'utf8'));
|
|
160
203
|
const flowState = JSON.parse(fs.readFileSync(path.join(path.dirname(root), 'flow', 'runs', 'local-request', 'state.json'), 'utf8'));
|
|
161
|
-
if (current.active_flow_id !== 'builder.build' || current.active_step_id !== '
|
|
162
|
-
if (state.status !== '
|
|
204
|
+
if (current.active_flow_id !== 'builder.build' || current.active_step_id !== 'design-probe') process.exit(1);
|
|
205
|
+
if (state.status !== 'in_progress' || state.phase !== 'pickup') process.exit(1);
|
|
163
206
|
if (JSON.stringify(state.work_item_refs) !== JSON.stringify(['local:local-request'])) process.exit(1);
|
|
164
207
|
if (workItem.id !== 'local-request' || workItem.title !== 'Local request') process.exit(1);
|
|
165
208
|
if (workItem.source_provider?.kind !== 'local' || workItem.source_provider?.path !== 'work-item.json') process.exit(1);
|
|
166
|
-
if (flowState.current_step !== '
|
|
167
|
-
if (state.flow_run?.current_step !== '
|
|
168
|
-
if (JSON.stringify(state.next_action?.skills) !== JSON.stringify(['
|
|
169
|
-
if (!state.next_action?.command?.includes('
|
|
209
|
+
if (flowState.current_step !== 'design-probe' || flowState.subject !== 'local:local-request') process.exit(1);
|
|
210
|
+
if (state.flow_run?.current_step !== 'design-probe') process.exit(1);
|
|
211
|
+
if (JSON.stringify(state.next_action?.skills) !== JSON.stringify(['pickup-probe'])) process.exit(1);
|
|
212
|
+
if (!state.next_action?.command?.includes("'workflow' 'status'")) process.exit(1);
|
|
170
213
|
if ('enforcement' in state.next_action) process.exit(1);
|
|
214
|
+
const bundle = JSON.parse(fs.readFileSync(path.join(root, 'local-request', 'trust.bundle'), 'utf8'));
|
|
215
|
+
const selected = (bundle.claims || []).find((claim) => claim.claimType === 'builder.pull-work.selected');
|
|
216
|
+
if (selected?.status !== 'verified') process.exit(1);
|
|
217
|
+
if (selected?.metadata?.workflow_subject_ref !== 'local:local-request') process.exit(1);
|
|
218
|
+
if (!(selected?.metadata?.artifact_refs || []).some((ref) => ref.file === '.kontourai/flow-agents/assignment/local-request.json')) process.exit(1);
|
|
171
219
|
NODE
|
|
172
220
|
then
|
|
173
|
-
pass "
|
|
221
|
+
pass "durably acquired local Work Item satisfies pull-work through the trust bundle and Flow advances"
|
|
174
222
|
else
|
|
175
223
|
fail "local Work Item or first-step state is invalid"
|
|
176
224
|
fi
|
|
@@ -183,6 +231,7 @@ FLOW_DIGEST_BEFORE="$(find "$TMP/local/.kontourai/flow/runs/local-request" -type
|
|
|
183
231
|
if flow_agents_node "$WRITER" ensure-session \
|
|
184
232
|
--artifact-root "$LOCAL_ROOT" \
|
|
185
233
|
--task-slug local-request \
|
|
234
|
+
--actor builder-entry-local \
|
|
186
235
|
--title "Local request" \
|
|
187
236
|
--summary "Providerless work still needs an anchor." \
|
|
188
237
|
--flow-id builder.build \
|
|
@@ -195,10 +244,10 @@ const project = process.argv[2];
|
|
|
195
244
|
const session = process.argv[3];
|
|
196
245
|
const flowState = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow', 'runs', 'local-request', 'state.json'), 'utf8'));
|
|
197
246
|
const sidecar = JSON.parse(fs.readFileSync(path.join(session, 'state.json'), 'utf8'));
|
|
198
|
-
if (flowState.current_step !== '
|
|
199
|
-
if (sidecar.flow_run?.current_step !== '
|
|
200
|
-
if (JSON.stringify(sidecar.next_action?.skills) !== JSON.stringify(['
|
|
201
|
-
if (!sidecar.next_action?.command?.includes('
|
|
247
|
+
if (flowState.current_step !== 'design-probe' || flowState.subject !== 'local:local-request') process.exit(1);
|
|
248
|
+
if (sidecar.flow_run?.current_step !== 'design-probe') process.exit(1);
|
|
249
|
+
if (JSON.stringify(sidecar.next_action?.skills) !== JSON.stringify(['pickup-probe'])) process.exit(1);
|
|
250
|
+
if (!sidecar.next_action?.command?.includes("'workflow' 'status'")) process.exit(1);
|
|
202
251
|
NODE
|
|
203
252
|
then
|
|
204
253
|
pass "repeated ensure-session loads the canonical Flow run without resetting its history"
|
|
@@ -213,19 +262,20 @@ printf 'not a run-store directory\n' > "$BROKEN_PROJECT/.kontourai/flow"
|
|
|
213
262
|
if flow_agents_node "$WRITER" ensure-session \
|
|
214
263
|
--artifact-root "$BROKEN_ROOT" \
|
|
215
264
|
--task-slug broken-start \
|
|
265
|
+
--actor builder-entry-broken \
|
|
216
266
|
--title "Broken start" \
|
|
217
267
|
--summary "Flow startup must fail visibly." \
|
|
218
268
|
--flow-id builder.build >"$TMP/broken-start.out" 2>&1; then
|
|
219
269
|
fail "invalid canonical Flow startup should fail ensure-session"
|
|
220
270
|
elif [[ -f "$BROKEN_ROOT/broken-start/state.json" ]] \
|
|
221
271
|
&& [[ ! -e "$BROKEN_PROJECT/.kontourai/flow/runs/broken-start" ]] \
|
|
222
|
-
&& grep -q 'canonical Builder Flow
|
|
223
|
-
&& grep -q '
|
|
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" \
|
|
224
274
|
&& node - "$BROKEN_ROOT/broken-start/state.json" <<'NODE'
|
|
225
275
|
const fs = require('node:fs');
|
|
226
276
|
const state = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
|
|
227
277
|
if (state.flow_run) process.exit(1);
|
|
228
|
-
if (!state.next_action?.command?.includes('
|
|
278
|
+
if (!state.next_action?.command?.includes("'workflow' 'start'")) process.exit(1);
|
|
229
279
|
NODE
|
|
230
280
|
then
|
|
231
281
|
pass "failed canonical startup is visible and leaves only retryable sidecar guidance"
|
|
@@ -233,13 +283,30 @@ else
|
|
|
233
283
|
fail "failed canonical startup forged state or lost recovery guidance: $(cat "$TMP/broken-start.out")"
|
|
234
284
|
fi
|
|
235
285
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
--
|
|
239
|
-
--
|
|
240
|
-
--
|
|
241
|
-
|
|
242
|
-
|
|
286
|
+
rm -f "$BROKEN_PROJECT/.kontourai/flow"
|
|
287
|
+
if flow_agents_node "$WRITER" ensure-session \
|
|
288
|
+
--artifact-root "$BROKEN_ROOT" \
|
|
289
|
+
--task-slug broken-start \
|
|
290
|
+
--actor builder-entry-broken \
|
|
291
|
+
--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 \
|
|
294
|
+
&& node - "$BROKEN_PROJECT" <<'NODE'
|
|
295
|
+
const fs = require('node:fs');
|
|
296
|
+
const path = require('node:path');
|
|
297
|
+
const project = process.argv[2];
|
|
298
|
+
const flowState = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow', 'runs', 'broken-start', 'state.json'), 'utf8'));
|
|
299
|
+
const bundle = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow-agents', 'broken-start', 'trust.bundle'), 'utf8'));
|
|
300
|
+
if (flowState.current_step !== 'design-probe') process.exit(1);
|
|
301
|
+
if (!(bundle.claims || []).some((claim) => claim.claimType === 'builder.pull-work.selected' && claim.status === 'verified')) process.exit(1);
|
|
302
|
+
NODE
|
|
303
|
+
then
|
|
304
|
+
pass "interrupted Flow startup retries from exact persisted acquisition provenance"
|
|
305
|
+
else
|
|
306
|
+
fail "interrupted acquisition could not recover: $(cat "$TMP/broken-start-retry.out")"
|
|
307
|
+
fi
|
|
308
|
+
|
|
309
|
+
if node - "$TMP/local" "$LOCAL_SESSION" <<'NODE'
|
|
243
310
|
const fs = require('node:fs');
|
|
244
311
|
const path = require('node:path');
|
|
245
312
|
const project = process.argv[2];
|
|
@@ -251,9 +318,158 @@ if (sidecar.flow_run?.current_step !== 'design-probe') process.exit(1);
|
|
|
251
318
|
if (JSON.stringify(sidecar.next_action?.skills) !== JSON.stringify(['pickup-probe'])) process.exit(1);
|
|
252
319
|
NODE
|
|
253
320
|
then
|
|
254
|
-
pass "
|
|
321
|
+
pass "automatic selected-work claim synchronizes Flow and projects the next skill"
|
|
322
|
+
else
|
|
323
|
+
fail "automatic selected-work claim did not advance the canonical run"
|
|
324
|
+
fi
|
|
325
|
+
|
|
326
|
+
SKIPPED_ROOT="$TMP/skipped/.kontourai/flow-agents"
|
|
327
|
+
if flow_agents_node "$WRITER" ensure-session \
|
|
328
|
+
--artifact-root "$SKIPPED_ROOT" \
|
|
329
|
+
--task-slug skipped-ownership \
|
|
330
|
+
--actor builder-entry-skipped \
|
|
331
|
+
--skip-ownership-guard \
|
|
332
|
+
--title "Skipped ownership" \
|
|
333
|
+
--summary "Unproven ownership must remain at pull-work." \
|
|
334
|
+
--flow-id builder.build >"$TMP/skipped.out" 2>&1 \
|
|
335
|
+
&& node - "$TMP/skipped" <<'NODE'
|
|
336
|
+
const fs = require('node:fs');
|
|
337
|
+
const path = require('node:path');
|
|
338
|
+
const project = process.argv[2];
|
|
339
|
+
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
|
+
const sidecar = JSON.parse(fs.readFileSync(path.join(session, 'state.json'), 'utf8'));
|
|
342
|
+
if (flowState.current_step !== 'pull-work' || sidecar.flow_run?.current_step !== 'pull-work') process.exit(1);
|
|
343
|
+
if (JSON.stringify(sidecar.next_action?.skills) !== JSON.stringify(['pull-work'])) process.exit(1);
|
|
344
|
+
if (fs.existsSync(path.join(session, 'trust.bundle'))) process.exit(1);
|
|
345
|
+
if (fs.existsSync(path.join(project, '.kontourai', 'flow-agents', 'assignment', 'skipped-ownership.json'))) process.exit(1);
|
|
346
|
+
NODE
|
|
347
|
+
then
|
|
348
|
+
pass "skipped ownership remains at pull-work without selected-work evidence"
|
|
349
|
+
else
|
|
350
|
+
fail "unproven ownership advanced the canonical run: $(cat "$TMP/skipped.out")"
|
|
351
|
+
fi
|
|
352
|
+
|
|
353
|
+
MISMATCH_ROOT="$TMP/mismatched-subject/.kontourai/flow-agents"
|
|
354
|
+
if flow_agents_node "$WRITER" ensure-session \
|
|
355
|
+
--artifact-root "$MISMATCH_ROOT" \
|
|
356
|
+
--task-slug arbitrary-session-name \
|
|
357
|
+
--work-item "kontourai/flow-agents#541" \
|
|
358
|
+
--actor builder-entry-mismatch \
|
|
359
|
+
--title "Mismatched assignment subject" \
|
|
360
|
+
--summary "An arbitrary slug is not exact Work Item evidence." \
|
|
361
|
+
--flow-id builder.build >"$TMP/mismatched-subject.out" 2>&1 \
|
|
362
|
+
&& node - "$TMP/mismatched-subject" <<'NODE'
|
|
363
|
+
const fs = require('node:fs');
|
|
364
|
+
const path = require('node:path');
|
|
365
|
+
const project = process.argv[2];
|
|
366
|
+
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
|
+
const sidecar = JSON.parse(fs.readFileSync(path.join(session, 'state.json'), 'utf8'));
|
|
369
|
+
if (flowState.subject !== 'kontourai/flow-agents#541' || flowState.current_step !== 'pull-work') process.exit(1);
|
|
370
|
+
if (sidecar.flow_run?.current_step !== 'pull-work') process.exit(1);
|
|
371
|
+
if (fs.existsSync(path.join(session, 'trust.bundle'))) process.exit(1);
|
|
372
|
+
if (!fs.existsSync(path.join(project, '.kontourai', 'flow-agents', 'assignment', 'arbitrary-session-name.json'))) process.exit(1);
|
|
373
|
+
NODE
|
|
374
|
+
then
|
|
375
|
+
pass "assignment subject must canonically match the exact Work Item before pull-work can pass"
|
|
376
|
+
else
|
|
377
|
+
fail "mismatched assignment subject was treated as exact Work Item evidence: $(cat "$TMP/mismatched-subject.out")"
|
|
378
|
+
fi
|
|
379
|
+
|
|
380
|
+
COLLISION_ROOT="$TMP/collision/.kontourai/flow-agents"
|
|
381
|
+
if ! flow_agents_node "$WRITER" ensure-session \
|
|
382
|
+
--artifact-root "$COLLISION_ROOT" \
|
|
383
|
+
--work-item "owner/a.b#541" \
|
|
384
|
+
--actor builder-entry-collision \
|
|
385
|
+
--title "Collision seed" \
|
|
386
|
+
--summary "Bind the first exact Work Item." >/dev/null 2>&1; then
|
|
387
|
+
fail "collision fixture could not seed the first exact Work Item"
|
|
388
|
+
else
|
|
389
|
+
COLLISION_ASSIGNMENT="$COLLISION_ROOT/assignment/owner-a-b-541.json"
|
|
390
|
+
COLLISION_DIGEST="$(shasum -a 256 "$COLLISION_ASSIGNMENT")"
|
|
391
|
+
if flow_agents_node "$WRITER" ensure-session \
|
|
392
|
+
--artifact-root "$COLLISION_ROOT" \
|
|
393
|
+
--work-item "owner/a-b#541" \
|
|
394
|
+
--actor builder-entry-collision \
|
|
395
|
+
--title "Collision attempt" \
|
|
396
|
+
--summary "A colliding slug must not change the exact Work Item." \
|
|
397
|
+
--flow-id builder.build >"$TMP/collision.out" 2>&1; then
|
|
398
|
+
fail "colliding exact Work Item refs should be rejected"
|
|
399
|
+
elif grep -q 'already bound to Work Item "owner/a.b#541", not "owner/a-b#541"' "$TMP/collision.out" \
|
|
400
|
+
&& [[ "$COLLISION_DIGEST" == "$(shasum -a 256 "$COLLISION_ASSIGNMENT")" ]] \
|
|
401
|
+
&& [[ ! -e "$TMP/collision/.kontourai/flow/runs/owner-a-b-541" ]]; then
|
|
402
|
+
pass "colliding slugs cannot change an existing session's exact Work Item binding"
|
|
403
|
+
else
|
|
404
|
+
fail "slug collision mutated ownership or returned the wrong diagnostic: $(cat "$TMP/collision.out")"
|
|
405
|
+
fi
|
|
406
|
+
fi
|
|
407
|
+
|
|
408
|
+
ASSIGNMENT_ONLY_ROOT="$TMP/assignment-only-collision/.kontourai/flow-agents"
|
|
409
|
+
mkdir -p "$ASSIGNMENT_ONLY_ROOT/assignment"
|
|
410
|
+
cat >"$ASSIGNMENT_ONLY_ROOT/assignment/owner-a-b-542.json" <<'JSON'
|
|
411
|
+
{
|
|
412
|
+
"schema_version": "1.0",
|
|
413
|
+
"role": "AssignmentClaimRecord",
|
|
414
|
+
"subject_id": "owner-a-b-542",
|
|
415
|
+
"actor": { "runtime": "codex", "session_id": "interrupted", "host": "eval-host", "human": null },
|
|
416
|
+
"actor_key": "interrupted",
|
|
417
|
+
"work_item_ref": "owner/a.b#542",
|
|
418
|
+
"claimed_at": "2020-01-01T00:00:00Z",
|
|
419
|
+
"ttl_seconds": 1,
|
|
420
|
+
"branch": "agent/interrupted/owner-a-b-542",
|
|
421
|
+
"artifact_dir": "owner-a-b-542",
|
|
422
|
+
"status": "claimed",
|
|
423
|
+
"audit_trail": []
|
|
424
|
+
}
|
|
425
|
+
JSON
|
|
426
|
+
ASSIGNMENT_ONLY_FILE="$ASSIGNMENT_ONLY_ROOT/assignment/owner-a-b-542.json"
|
|
427
|
+
ASSIGNMENT_ONLY_DIGEST="$(shasum -a 256 "$ASSIGNMENT_ONLY_FILE")"
|
|
428
|
+
if flow_agents_node "$WRITER" ensure-session \
|
|
429
|
+
--artifact-root "$ASSIGNMENT_ONLY_ROOT" \
|
|
430
|
+
--work-item "owner/a-b#542" \
|
|
431
|
+
--actor builder-entry-assignment-only-collision \
|
|
432
|
+
--supersede-stale \
|
|
433
|
+
--now "2026-07-10T00:00:00Z" \
|
|
434
|
+
--title "Assignment-only collision" \
|
|
435
|
+
--summary "A crash before state creation must preserve exact assignment identity." \
|
|
436
|
+
--flow-id builder.build >"$TMP/assignment-only-collision.out" 2>&1; then
|
|
437
|
+
fail "assignment-only colliding Work Item should be rejected"
|
|
438
|
+
elif grep -q 'already bound to Work Item "owner/a.b#542", not "owner/a-b#542"' "$TMP/assignment-only-collision.out" \
|
|
439
|
+
&& [[ "$ASSIGNMENT_ONLY_DIGEST" == "$(shasum -a 256 "$ASSIGNMENT_ONLY_FILE")" ]] \
|
|
440
|
+
&& [[ ! -e "$ASSIGNMENT_ONLY_ROOT/owner-a-b-542" ]]; then
|
|
441
|
+
pass "assignment provenance blocks slug collisions before session state exists"
|
|
442
|
+
else
|
|
443
|
+
fail "assignment-only collision mutated provenance or returned the wrong diagnostic: $(cat "$TMP/assignment-only-collision.out")"
|
|
444
|
+
fi
|
|
445
|
+
|
|
446
|
+
PREEXISTING_ROOT="$TMP/preexisting/.kontourai/flow-agents"
|
|
447
|
+
if flow_agents_node "$WRITER" ensure-session \
|
|
448
|
+
--artifact-root "$PREEXISTING_ROOT" \
|
|
449
|
+
--task-slug preexisting-selection \
|
|
450
|
+
--actor builder-entry-preexisting \
|
|
451
|
+
--title "Preexisting selection" \
|
|
452
|
+
--summary "Seed an assignment before the canonical Builder run." >/dev/null 2>&1 \
|
|
453
|
+
&& flow_agents_node "$WRITER" ensure-session \
|
|
454
|
+
--artifact-root "$PREEXISTING_ROOT" \
|
|
455
|
+
--task-slug preexisting-selection \
|
|
456
|
+
--actor builder-entry-preexisting \
|
|
457
|
+
--title "Preexisting selection" \
|
|
458
|
+
--summary "An older self-held assignment is not new selection evidence." \
|
|
459
|
+
--flow-id builder.build >"$TMP/preexisting.out" 2>&1 \
|
|
460
|
+
&& node - "$TMP/preexisting" <<'NODE'
|
|
461
|
+
const fs = require('node:fs');
|
|
462
|
+
const path = require('node:path');
|
|
463
|
+
const project = process.argv[2];
|
|
464
|
+
const session = path.join(project, '.kontourai', 'flow-agents', 'preexisting-selection');
|
|
465
|
+
const flowState = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow', 'runs', 'preexisting-selection', 'state.json'), 'utf8'));
|
|
466
|
+
if (flowState.current_step !== 'pull-work') process.exit(1);
|
|
467
|
+
if (fs.existsSync(path.join(session, 'trust.bundle'))) process.exit(1);
|
|
468
|
+
NODE
|
|
469
|
+
then
|
|
470
|
+
pass "preexisting self-held assignments do not retroactively satisfy pull-work"
|
|
255
471
|
else
|
|
256
|
-
fail "
|
|
472
|
+
fail "preexisting assignment was treated as current selection evidence: $(cat "$TMP/preexisting.out")"
|
|
257
473
|
fi
|
|
258
474
|
|
|
259
475
|
if FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_MAX_BLOCKS=100000 \
|
|
@@ -266,12 +482,13 @@ else
|
|
|
266
482
|
stop_status=$?
|
|
267
483
|
if [[ "$stop_status" -eq 2 ]] \
|
|
268
484
|
&& grep -q 'required skills: pickup-probe' "$TMP/stop.err" \
|
|
269
|
-
&& grep -q '
|
|
485
|
+
&& grep -q 'next command: sh -c' "$TMP/stop.err" \
|
|
270
486
|
&& grep -q 'release skipped for active Flow run' "$TMP/stop.err" \
|
|
271
487
|
&& node - "$LOCAL_SESSION/state.json" <<'NODE'
|
|
272
488
|
const fs = require('node:fs');
|
|
273
489
|
const state = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
|
|
274
490
|
if (state.flow_run?.status !== 'active' || state.flow_run?.current_step !== 'design-probe') process.exit(1);
|
|
491
|
+
if (!state.next_action?.command?.includes("'workflow' 'status'")) process.exit(1);
|
|
275
492
|
NODE
|
|
276
493
|
then
|
|
277
494
|
pass "active Flow run blocks Stop, preserves liveness, and exposes executable guidance"
|
|
@@ -881,6 +881,103 @@ else
|
|
|
881
881
|
_fail "Codex full install lost Builder specialist role routing"
|
|
882
882
|
fi
|
|
883
883
|
|
|
884
|
+
echo ""
|
|
885
|
+
echo "--- Packed Package Builder Entry ---"
|
|
886
|
+
PACKAGE_CONSUMER="$TMPDIR_EVAL/package-consumer"
|
|
887
|
+
PACKAGE_PROJECT="$TMPDIR_EVAL/package-project"
|
|
888
|
+
PACKAGE_AMBIENT="$TMPDIR_EVAL/package-ambient"
|
|
889
|
+
mkdir -p "$PACKAGE_CONSUMER" "$PACKAGE_PROJECT/.kontourai/flow-agents" "$PACKAGE_AMBIENT/kits/builder/flows"
|
|
890
|
+
cat >"$PACKAGE_AMBIENT/kits/builder/flows/build.flow.json" <<'JSON'
|
|
891
|
+
{
|
|
892
|
+
"id": "builder.build",
|
|
893
|
+
"version": "poison-ambient-cwd",
|
|
894
|
+
"steps": [{ "id": "ambient-poison", "next": null }],
|
|
895
|
+
"gates": {}
|
|
896
|
+
}
|
|
897
|
+
JSON
|
|
898
|
+
PACKAGE_PACK_LOG="$TMPDIR_EVAL/package-pack.log"
|
|
899
|
+
PACKAGE_CLI="$PACKAGE_CONSUMER/node_modules/@kontourai/flow-agents/build/src/cli.js"
|
|
900
|
+
PACKAGE_SESSION="$PACKAGE_PROJECT/.kontourai/flow-agents/packed-builder-entry"
|
|
901
|
+
if (cd "$ROOT_DIR" && npm pack --silent --pack-destination "$TMPDIR_EVAL" >"$PACKAGE_PACK_LOG") \
|
|
902
|
+
&& PACKAGE_TARBALL="$(find "$TMPDIR_EVAL" -maxdepth 1 -type f -name 'kontourai-flow-agents-*.tgz' -print -quit)" \
|
|
903
|
+
&& [[ -n "$PACKAGE_TARBALL" ]] \
|
|
904
|
+
&& npm install --silent --no-audit --no-fund --ignore-scripts --prefix "$PACKAGE_CONSUMER" "$PACKAGE_TARBALL" \
|
|
905
|
+
&& (cd "$PACKAGE_AMBIENT" && CODEX_SESSION_ID=packed-package-consumer node "$PACKAGE_CONSUMER/node_modules/@kontourai/flow-agents/build/src/cli/workflow-sidecar.js" ensure-session \
|
|
906
|
+
--artifact-root "$PACKAGE_PROJECT/.kontourai/flow-agents" \
|
|
907
|
+
--task-slug packed-builder-entry \
|
|
908
|
+
--title "Packed Builder entry" \
|
|
909
|
+
--summary "Installed package should project pickup-probe." \
|
|
910
|
+
--flow-id builder.build >/dev/null 2>&1) \
|
|
911
|
+
&& node - "$PACKAGE_PROJECT" <<'NODE' &&
|
|
912
|
+
const fs = require('node:fs');
|
|
913
|
+
const path = require('node:path');
|
|
914
|
+
const project = process.argv[2];
|
|
915
|
+
const state = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow-agents', 'packed-builder-entry', 'state.json'), 'utf8'));
|
|
916
|
+
const flow = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow', 'runs', 'packed-builder-entry', 'state.json'), 'utf8'));
|
|
917
|
+
const bundle = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow-agents', 'packed-builder-entry', 'trust.bundle'), 'utf8'));
|
|
918
|
+
if (flow.current_step !== 'design-probe' || state.flow_run?.current_step !== 'design-probe') process.exit(1);
|
|
919
|
+
if (JSON.stringify(state.next_action?.skills) !== JSON.stringify(['pickup-probe'])) process.exit(1);
|
|
920
|
+
if (!(bundle.claims || []).some((claim) => claim.claimType === 'builder.pull-work.selected' && claim.status === 'verified')) process.exit(1);
|
|
921
|
+
NODE
|
|
922
|
+
node --input-type=module - "$PACKAGE_PROJECT" "$PACKAGE_CONSUMER" <<'NODE' &&
|
|
923
|
+
import fs from 'node:fs';
|
|
924
|
+
import path from 'node:path';
|
|
925
|
+
import { generateKeyPairSync, sign } from 'node:crypto';
|
|
926
|
+
import { pathToFileURL } from 'node:url';
|
|
927
|
+
const [project, consumer] = process.argv.slice(2);
|
|
928
|
+
const slug = 'packed-builder-entry';
|
|
929
|
+
const assignment = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow-agents', 'assignment', `${slug}.json`), 'utf8'));
|
|
930
|
+
const state = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow-agents', slug, 'state.json'), 'utf8'));
|
|
931
|
+
const packageEntry = path.join(consumer, 'node_modules', '@kontourai', 'flow-agents', 'build', 'src', 'index.js');
|
|
932
|
+
const { builderLifecycleAuthorizationPayload } = await import(pathToFileURL(packageEntry).href);
|
|
933
|
+
const keys = generateKeyPairSync('ed25519');
|
|
934
|
+
const keyId = 'packed-consumer';
|
|
935
|
+
fs.mkdirSync(path.join(project, '.flow-agents'), { recursive: true });
|
|
936
|
+
fs.writeFileSync(path.join(project, '.flow-agents', 'lifecycle-authority-keys.json'), JSON.stringify({
|
|
937
|
+
schema_version: '1.0',
|
|
938
|
+
keys: [{ id: keyId, algorithm: 'ed25519', public_key_pem: keys.publicKey.export({ type: 'spki', format: 'pem' }) }],
|
|
939
|
+
}, null, 2));
|
|
940
|
+
for (const operation of ['cancel', 'archive']) {
|
|
941
|
+
const requestedAt = new Date();
|
|
942
|
+
const unsigned = {
|
|
943
|
+
schema_version: '1.0',
|
|
944
|
+
operation,
|
|
945
|
+
run_id: slug,
|
|
946
|
+
subject: state.work_item_refs[0],
|
|
947
|
+
assignment_actor_key: assignment.actor_key,
|
|
948
|
+
assignment_actor: { ...assignment.actor, human: assignment.actor.human ?? null },
|
|
949
|
+
nonce: `packed-${operation}`,
|
|
950
|
+
expires_at: new Date(requestedAt.getTime() + 60 * 60_000).toISOString(),
|
|
951
|
+
request: {
|
|
952
|
+
reason: `packed consumer ${operation}`,
|
|
953
|
+
authority: { kind: 'user_request', actor: 'packed-fixture', request_ref: `fixture://packed/${operation}`, requested_at: requestedAt.toISOString() },
|
|
954
|
+
},
|
|
955
|
+
};
|
|
956
|
+
const authorization = { ...unsigned, signature: { algorithm: 'ed25519', key_id: keyId, value: sign(null, Buffer.from(builderLifecycleAuthorizationPayload(unsigned)), keys.privateKey).toString('base64') } };
|
|
957
|
+
fs.writeFileSync(path.join(project, `${operation}.authorization.json`), JSON.stringify(authorization, null, 2));
|
|
958
|
+
}
|
|
959
|
+
NODE
|
|
960
|
+
(cd "$PACKAGE_PROJECT" && CODEX_SESSION_ID=packed-package-consumer node "$PACKAGE_CLI" builder-run pause --session-dir "$PACKAGE_SESSION" --reason "packed pause" >/dev/null) \
|
|
961
|
+
&& (cd "$PACKAGE_PROJECT" && CODEX_SESSION_ID=packed-package-consumer node "$PACKAGE_CLI" builder-run resume --session-dir "$PACKAGE_SESSION" --reason "packed resume" >/dev/null) \
|
|
962
|
+
&& (cd "$PACKAGE_PROJECT" && node "$PACKAGE_CLI" builder-run cancel --session-dir "$PACKAGE_SESSION" --authorization-file "$PACKAGE_PROJECT/cancel.authorization.json" >/dev/null) \
|
|
963
|
+
&& (cd "$PACKAGE_PROJECT" && node "$PACKAGE_CLI" builder-run archive --session-dir "$PACKAGE_SESSION" --authorization-file "$PACKAGE_PROJECT/archive.authorization.json" >/dev/null) \
|
|
964
|
+
&& node - "$PACKAGE_PROJECT" <<'NODE'
|
|
965
|
+
const fs = require('node:fs');
|
|
966
|
+
const path = require('node:path');
|
|
967
|
+
const project = process.argv[2];
|
|
968
|
+
const slug = 'packed-builder-entry';
|
|
969
|
+
const archived = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow-agents', 'archive', slug, 'state.json'), 'utf8'));
|
|
970
|
+
const flow = JSON.parse(fs.readFileSync(path.join(project, '.kontourai', 'flow', 'runs', slug, 'state.json'), 'utf8'));
|
|
971
|
+
const consumed = fs.readdirSync(path.join(project, '.kontourai', 'flow-agents', 'lifecycle-authority', 'consumed'));
|
|
972
|
+
if (archived.status !== 'archived' || flow.status !== 'canceled' || consumed.length !== 2) process.exit(1);
|
|
973
|
+
if (fs.existsSync(path.join(project, '.kontourai', 'flow-agents', slug))) process.exit(1);
|
|
974
|
+
NODE
|
|
975
|
+
then
|
|
976
|
+
_pass "packed npm consumer projects Builder entry and executes lifecycle commands"
|
|
977
|
+
else
|
|
978
|
+
_fail "packed npm consumer did not execute canonical Builder entry and lifecycle commands"
|
|
979
|
+
fi
|
|
980
|
+
|
|
884
981
|
if [[ -d "$CODEX_FULL_DEST/.codex/skills/plan-work" && -d "$CODEX_FULL_DEST/.codex/skills/deliver" && -d "$CODEX_FULL_DEST/.codex/skills/agentic-engineering" ]]; then
|
|
885
982
|
_pass "Codex full install ships kit-skills and standalone skills together"
|
|
886
983
|
else
|
|
@@ -377,6 +377,7 @@ flow_agents_node "workflow-sidecar" ensure-session \
|
|
|
377
377
|
--task-slug gate-actor-a \
|
|
378
378
|
--actor eval-actor-a-session \
|
|
379
379
|
--flow-id builder.build \
|
|
380
|
+
--skip-ownership-guard \
|
|
380
381
|
--source-request "Actor A is active on a FlowDefinition-driven session." \
|
|
381
382
|
--summary "Actor A, builder.build, pull-work step." \
|
|
382
383
|
--timestamp "2026-07-01T00:00:00Z" \
|
|
@@ -258,6 +258,7 @@ if flow_agents_node "$WRITER" ensure-session \
|
|
|
258
258
|
--artifact-root "$SESSION_ROOT" \
|
|
259
259
|
--task-slug dual-emit-test \
|
|
260
260
|
--flow-id builder.build \
|
|
261
|
+
--skip-ownership-guard \
|
|
261
262
|
--title "Declared-Only Test" \
|
|
262
263
|
--summary "Test declared-only emit for ADR 0016 P-d." \
|
|
263
264
|
--criterion "Tests pass" \
|
|
@@ -348,6 +349,7 @@ if flow_agents_node "$WRITER" ensure-session \
|
|
|
348
349
|
--artifact-root "$SESSION_ROOT" \
|
|
349
350
|
--task-slug dual-emit-policy \
|
|
350
351
|
--flow-id builder.build \
|
|
352
|
+
--skip-ownership-guard \
|
|
351
353
|
--title "Declared Policy Test" \
|
|
352
354
|
--summary "Test declared-only policy emit for ADR 0016 P-d." \
|
|
353
355
|
--criterion "Policy passes" \
|
|
@@ -51,6 +51,7 @@ mkdir -p "$MAIN_AROOT"
|
|
|
51
51
|
if flow_agents_node "$WRITER" ensure-session \
|
|
52
52
|
--artifact-root "$MAIN_AROOT" \
|
|
53
53
|
--task-slug "$SLUG" \
|
|
54
|
+
--actor activation-test-actor \
|
|
54
55
|
--title "Step 1 activation test" \
|
|
55
56
|
--summary "Test that --flow-id builder.build activates the FlowDefinition-driven path." \
|
|
56
57
|
--criterion "All gates produce declared claims" \
|
|
@@ -65,12 +66,14 @@ node -e "
|
|
|
65
66
|
const fs = require('fs');
|
|
66
67
|
const c = JSON.parse(fs.readFileSync('$MAIN_AROOT/current.json', 'utf8'));
|
|
67
68
|
const flow = JSON.parse(fs.readFileSync('$TMP/main-project/.kontourai/flow/runs/$SLUG/state.json', 'utf8'));
|
|
69
|
+
const bundle = JSON.parse(fs.readFileSync('$SESSION_DIR/trust.bundle', 'utf8'));
|
|
68
70
|
if (c.active_flow_id !== 'builder.build') throw new Error('expected active_flow_id=builder.build, got ' + c.active_flow_id);
|
|
69
|
-
if (
|
|
70
|
-
if (flow.status !== 'active' || flow.current_step !== '
|
|
71
|
+
if (c.active_step_id !== 'design-probe') throw new Error('expected active_step_id=design-probe, got ' + c.active_step_id);
|
|
72
|
+
if (flow.status !== 'active' || flow.current_step !== 'design-probe') throw new Error('canonical Flow did not advance through trusted selection: ' + JSON.stringify(flow));
|
|
73
|
+
if (!(bundle.claims || []).some((claim) => claim.claimType === 'builder.pull-work.selected' && claim.status === 'verified')) throw new Error('missing verified selected-work claim');
|
|
71
74
|
console.log('current.json: active_flow_id=' + c.active_flow_id + ' active_step_id=' + c.active_step_id);
|
|
72
75
|
" 2>&1 \
|
|
73
|
-
&& _pass "ensure-session
|
|
76
|
+
&& _pass "ensure-session records trusted selection and projects the canonical Flow run at design-probe" \
|
|
74
77
|
|| _fail "ensure-session did not create and project the canonical Flow run"
|
|
75
78
|
|
|
76
79
|
# ─── TEST 2: advance-state sets active_step_id via phase_map ─────────────────
|
|
@@ -15,10 +15,10 @@ _pass() { echo " ✓ $1"; }
|
|
|
15
15
|
_fail() { echo " ✗ $1"; errors=$((errors + 1)); }
|
|
16
16
|
|
|
17
17
|
REPO="$TMPDIR_EVAL/repo"
|
|
18
|
-
mkdir -p "$REPO/.flow-agents/stuck"
|
|
18
|
+
mkdir -p "$REPO/.kontourai/flow-agents/stuck"
|
|
19
19
|
printf '# Test Repo\n' > "$REPO/AGENTS.md"
|
|
20
20
|
printf '# Stuck\n\nbranch: main\nstatus: executing\ntype: deliver\n\n## Plan\n\nTBD.\n' \
|
|
21
|
-
> "$REPO/.flow-agents/stuck/stuck--deliver.md"
|
|
21
|
+
> "$REPO/.kontourai/flow-agents/stuck/stuck--deliver.md"
|
|
22
22
|
|
|
23
23
|
PAYLOAD="{\"hook_event_name\":\"Stop\",\"cwd\":\"$REPO\"}"
|
|
24
24
|
|
|
@@ -54,7 +54,7 @@ c4=$(run_block "$TMPDIR_EVAL/b4.err")
|
|
|
54
54
|
printf '%s' "$PAYLOAD" | FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_MAX_BLOCKS=3 node "$ROOT/scripts/hooks/stop-goal-fit.js" >/dev/null 2>/dev/null
|
|
55
55
|
# mutate the artifact so the warning set differs
|
|
56
56
|
printf '# Stuck\n\nbranch: main\nstatus: verifying\ntype: deliver\n\n## Plan\n\nDifferent.\n' \
|
|
57
|
-
> "$REPO/.flow-agents/stuck/stuck--deliver.md"
|
|
57
|
+
> "$REPO/.kontourai/flow-agents/stuck/stuck--deliver.md"
|
|
58
58
|
cd=$(run_block "$TMPDIR_EVAL/bd.err")
|
|
59
59
|
[[ "$cd" -eq 2 ]] && rg -q 'Stop blocked .* \(block 1; after 3 identical blocks' "$TMPDIR_EVAL/bd.err" \
|
|
60
60
|
&& _pass "changed goal-fit gap resets the streak to 1/3" \
|
|
@@ -129,6 +129,7 @@ flow_agents_node "workflow-sidecar" ensure-session \
|
|
|
129
129
|
--title "Ensure Default Step" \
|
|
130
130
|
--summary "Test ensure-session default step." \
|
|
131
131
|
--flow-id builder.build \
|
|
132
|
+
--skip-ownership-guard \
|
|
132
133
|
--timestamp "2026-06-26T00:00:00Z" >/dev/null 2>&1
|
|
133
134
|
|
|
134
135
|
node -e "
|
|
@@ -154,6 +155,7 @@ flow_agents_node "workflow-sidecar" ensure-session \
|
|
|
154
155
|
--title "Gate Claim Test" \
|
|
155
156
|
--summary "Test gate claim producer." \
|
|
156
157
|
--flow-id builder.build \
|
|
158
|
+
--skip-ownership-guard \
|
|
157
159
|
--timestamp "2026-06-26T00:00:00Z" >/dev/null 2>&1
|
|
158
160
|
|
|
159
161
|
flow_agents_node "workflow-sidecar" init-plan "$CLAIM_ROOT/gate-claim/gate-claim--deliver.md" \
|
|
@@ -261,6 +263,7 @@ flow_agents_node "workflow-sidecar" ensure-session \
|
|
|
261
263
|
--title "Tamper Test" \
|
|
262
264
|
--summary "Testing tamper detection." \
|
|
263
265
|
--flow-id builder.build \
|
|
266
|
+
--skip-ownership-guard \
|
|
264
267
|
--timestamp "2026-06-26T00:00:00Z" >/dev/null 2>&1
|
|
265
268
|
|
|
266
269
|
flow_agents_node "workflow-sidecar" init-plan "$T_DIR/.kontourai/flow-agents/tamper/tamper--deliver.md" \
|
|
@@ -364,6 +367,7 @@ flow_agents_node "workflow-sidecar" ensure-session \
|
|
|
364
367
|
--title "Clean Test" \
|
|
365
368
|
--summary "Testing clean gate claim." \
|
|
366
369
|
--flow-id builder.build \
|
|
370
|
+
--skip-ownership-guard \
|
|
367
371
|
--timestamp "2026-06-26T00:00:00Z" >/dev/null 2>&1
|
|
368
372
|
|
|
369
373
|
flow_agents_node "workflow-sidecar" init-plan "$C_DIR/.kontourai/flow-agents/clean/clean--deliver.md" \
|