@kontourai/flow-agents 3.5.0 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/.github/workflows/ci.yml +4 -0
  2. package/CHANGELOG.md +15 -0
  3. package/build/src/builder-flow-run-adapter.d.ts +32 -3
  4. package/build/src/builder-flow-run-adapter.js +113 -20
  5. package/build/src/builder-flow-runtime.d.ts +26 -3
  6. package/build/src/builder-flow-runtime.js +502 -49
  7. package/build/src/builder-lifecycle-authority.d.ts +35 -0
  8. package/build/src/builder-lifecycle-authority.js +219 -0
  9. package/build/src/cli/assignment-provider.d.ts +14 -7
  10. package/build/src/cli/assignment-provider.js +128 -65
  11. package/build/src/cli/builder-run.js +46 -9
  12. package/build/src/cli/workflow-artifact-cleanup-audit.js +3 -0
  13. package/build/src/cli/workflow-sidecar.d.ts +30 -3
  14. package/build/src/cli/workflow-sidecar.js +825 -99
  15. package/build/src/cli/workflow.d.ts +2 -0
  16. package/build/src/cli/workflow.js +769 -0
  17. package/build/src/cli.js +2 -0
  18. package/build/src/flow-kit/validate.d.ts +17 -0
  19. package/build/src/flow-kit/validate.js +340 -2
  20. package/build/src/index.d.ts +4 -0
  21. package/build/src/index.js +7 -5
  22. package/build/src/lib/observed-command.d.ts +7 -0
  23. package/build/src/lib/observed-command.js +100 -0
  24. package/build/src/lib/package-version.d.ts +2 -0
  25. package/build/src/lib/package-version.js +13 -0
  26. package/build/src/lib/pinned-cli-command.d.ts +6 -0
  27. package/build/src/lib/pinned-cli-command.js +21 -0
  28. package/build/src/tools/generate-context-map.js +5 -3
  29. package/context/contracts/artifact-contract.md +1 -1
  30. package/context/scripts/hooks/config-protection.js +8 -1
  31. package/context/scripts/hooks/lib/config-protection-remedies.js +3 -0
  32. package/context/scripts/hooks/lib/kit-catalog.js +1 -1
  33. package/context/scripts/hooks/stop-goal-fit.js +79 -10
  34. package/docs/context-map.md +24 -20
  35. package/docs/developer-architecture.md +1 -1
  36. package/docs/public-workflow-cli.md +132 -0
  37. package/docs/skills-map.md +51 -27
  38. package/docs/spec/builder-flow-runtime.md +78 -40
  39. package/docs/workflow-usage-guide.md +110 -38
  40. package/evals/ci/run-baseline.sh +2 -0
  41. package/evals/fixtures/hook-influence/cases.json +2 -2
  42. package/evals/integration/test_builder_entry_enforcement.sh +57 -45
  43. package/evals/integration/test_builder_step_producers.sh +297 -6
  44. package/evals/integration/test_bundle_install.sh +258 -55
  45. package/evals/integration/test_critique_supersession_roundtrip.sh +21 -8
  46. package/evals/integration/test_current_json_per_actor.sh +12 -0
  47. package/evals/integration/test_dual_emit_flow_step.sh +62 -43
  48. package/evals/integration/test_flowdef_session_activation.sh +145 -25
  49. package/evals/integration/test_flowdef_session_history_preservation.sh +23 -21
  50. package/evals/integration/test_gate_lockdown.sh +3 -5
  51. package/evals/integration/test_goal_fit_hook.sh +60 -2
  52. package/evals/integration/test_liveness_verdict.sh +14 -17
  53. package/evals/integration/test_phase_map_and_gate_claim.sh +63 -38
  54. package/evals/integration/test_public_workflow_cli.sh +573 -0
  55. package/evals/integration/test_pull_work_liveness_preflight.sh +22 -66
  56. package/evals/integration/test_sidecar_field_preservation.sh +36 -11
  57. package/evals/integration/test_workflow_sidecar_writer.sh +277 -44
  58. package/evals/integration/test_workflow_steering_hook.sh +15 -38
  59. package/evals/run.sh +2 -0
  60. package/evals/static/test_builder_skill_coherence.sh +247 -0
  61. package/evals/static/test_library_exports.sh +5 -2
  62. package/evals/static/test_workflow_skills.sh +13 -325
  63. package/kits/builder/flows/build.flow.json +22 -0
  64. package/kits/builder/flows/shape.flow.json +9 -9
  65. package/kits/builder/kit.json +70 -16
  66. package/kits/builder/skills/builder-shape/SKILL.md +75 -75
  67. package/kits/builder/skills/continue-work/SKILL.md +45 -106
  68. package/kits/builder/skills/deliver/SKILL.md +96 -442
  69. package/kits/builder/skills/design-probe/SKILL.md +40 -139
  70. package/kits/builder/skills/evidence-gate/SKILL.md +59 -201
  71. package/kits/builder/skills/execute-plan/SKILL.md +54 -125
  72. package/kits/builder/skills/fix-bug/SKILL.md +42 -132
  73. package/kits/builder/skills/gate-review/SKILL.md +60 -211
  74. package/kits/builder/skills/idea-to-backlog/SKILL.md +63 -244
  75. package/kits/builder/skills/learning-review/SKILL.md +63 -170
  76. package/kits/builder/skills/pickup-probe/SKILL.md +54 -111
  77. package/kits/builder/skills/plan-work/SKILL.md +51 -185
  78. package/kits/builder/skills/pull-work/SKILL.md +136 -485
  79. package/kits/builder/skills/release-readiness/SKILL.md +66 -107
  80. package/kits/builder/skills/review-work/SKILL.md +89 -176
  81. package/kits/builder/skills/tdd-workflow/SKILL.md +53 -147
  82. package/kits/builder/skills/verify-work/SKILL.md +101 -113
  83. package/package.json +2 -2
  84. package/schemas/builder-lifecycle-authorization.schema.json +57 -0
  85. package/schemas/lifecycle-authority-keys.schema.json +25 -0
  86. package/schemas/workflow-state.schema.json +1 -1
  87. package/scripts/hooks/config-protection.js +8 -1
  88. package/scripts/hooks/lib/config-protection-remedies.js +3 -0
  89. package/scripts/hooks/lib/kit-catalog.js +1 -1
  90. package/scripts/hooks/stop-goal-fit.js +79 -10
  91. package/src/builder-flow-run-adapter.ts +156 -23
  92. package/src/builder-flow-runtime.ts +535 -53
  93. package/src/builder-lifecycle-authority.ts +218 -0
  94. package/src/cli/assignment-provider-lock.test.mjs +83 -0
  95. package/src/cli/assignment-provider.ts +91 -22
  96. package/src/cli/builder-flow-run-adapter.test.mjs +4 -2
  97. package/src/cli/builder-flow-runtime.test.mjs +597 -8
  98. package/src/cli/builder-run.ts +54 -9
  99. package/src/cli/kit-metadata-security.test.mjs +232 -6
  100. package/src/cli/public-api.test.mjs +15 -0
  101. package/src/cli/workflow-artifact-cleanup-audit.ts +3 -0
  102. package/src/cli/workflow-sidecar-execution-proof.test.mjs +90 -0
  103. package/src/cli/workflow-sidecar.ts +748 -99
  104. package/src/cli/workflow.ts +708 -0
  105. package/src/cli.ts +2 -0
  106. package/src/flow-kit/validate.ts +320 -2
  107. package/src/index.ts +20 -5
  108. package/src/lib/observed-command.ts +96 -0
  109. package/src/lib/package-version.ts +15 -0
  110. package/src/lib/pinned-cli-command.ts +23 -0
  111. package/src/tools/generate-context-map.ts +5 -3
@@ -126,7 +126,7 @@ fi
126
126
  # duplicate validation logic was introduced for resolve-slug.
127
127
  if flow_agents_node "$WRITER" resolve-slug 'owner/repo' >"$TMPDIR_EVAL/a6.out" 2>"$TMPDIR_EVAL/a6.err"; then
128
128
  _fail "resolve-slug should reject a ref with no # separator"
129
- elif rg -q -- 'owner/repo#id format' "$TMPDIR_EVAL/a6.err"; then
129
+ elif rg -q -- 'provider-neutral provider:id ref or owner/repo#numeric-id' "$TMPDIR_EVAL/a6.err"; then
130
130
  _pass "resolve-slug rejects a ref with no # separator using workItemSlug()'s existing message (AC7)"
131
131
  else
132
132
  _fail "resolve-slug malformed-ref rejection message mismatch: $(cat "$TMPDIR_EVAL/a6.out" "$TMPDIR_EVAL/a6.err")"
@@ -323,71 +323,27 @@ else
323
323
  _fail "liveness status unexpectedly did not acquire the lock — F1's bypass may have leaked beyond the whoami action: out=$(cat "$TMPDIR_EVAL/e3.out") err=$(cat "$TMPDIR_EVAL/e3.err")"
324
324
  fi
325
325
 
326
- # ─── D. Static skill-text assertions (AC6, AC8) ─────────────────────────────
327
- echo "--- D. Static skill-text assertions ---"
328
-
329
- require_text "$PULL" '### 1a\. Liveness Selection Preflight' "pull-work documents the Liveness Selection Preflight subsection (AC1, AC8)"
330
- require_text "$PULL" 'liveness whoami --json' "pull-work references liveness whoami --json by exact command name (AC1, AC8)"
331
- require_text "$PULL" 'liveness status --json' "pull-work references liveness status --json by exact command name (AC1, AC8)"
332
- require_text "$PULL" 'resolve-slug <owner>/<repo>#<issue-number>' "pull-work references resolve-slug by exact command name (AC1, AC4, AC8)"
333
- require_text "$PULL" 'liveness claim <subjectId>' "pull-work references liveness claim <subjectId> by exact command name (AC4, AC8)"
334
- require_text "$PULL" 'reading each row.s raw .status. field \(never .label.\)' "pull-work instructs consuming raw status, never label (AC1, AC8)"
335
- require_text "$PULL" 'a .verified. row for an actor other than self.*.held.' "pull-work documents held classification (AC1, AC2, AC8)"
336
- require_text "$PULL" 'excluded from the ready set by default' "pull-work excludes held candidates by default (AC2, AC8)"
337
- require_text "$PULL" 'effective_state: .reclaimable.' "pull-work documents reclaimable classification via the assignment-provider join (AC1, AC3, AC8, #290)"
338
- require_text "$PULL" 'requires an explicit recorded opt-in' "pull-work requires an explicit recorded opt-in for reclaimable selection (AC3, AC8)"
339
- require_text "$PULL" 'never a silent normal pick' "pull-work states reclaimable is never a silent normal pick (AC3, AC8)"
340
- require_text "$PULL" 'a .verified. row for the resolved self actor.*.mine.' "pull-work documents mine classification (AC1, AC5, AC8)"
341
- require_text "$PULL" 'do not re-offer as new, do not exclude as held-by-other' "pull-work folds own-actor mine into WIP logic, not re-offered or re-excluded (AC5, AC8)"
342
- require_text "$PULL" 'An explicit user instruction to proceed despite a .held. or .reclaimable. classification' "pull-work documents the --force/explicit-instruction override (AC2, AC3, AC8)"
343
- require_text "$PULL" '.--force.' "pull-work names --force as the override mechanism (AC2, AC8)"
344
- require_text "$PULL" 'override and its stated reason must be recorded in the artifact' "pull-work requires the override + reason to be recorded (AC2, AC8)"
345
- require_text "$PULL" 'do not mutate GitHub Projects, provider fields, or cross-repo provider state from this skill' "pull-work's existing no-provider-mutation sentence is present verbatim and unchanged (AC6, AC8)"
346
- require_text "$PULL" 'read/write the local runtime liveness stream, never GitHub issue/label/assignee state' "pull-work states the liveness claim is local runtime state, not a provider mutation (AC6, AC8)"
347
- require_text "$PULL" 'this is not\s*$|this is not a provider mutation' "pull-work explicitly states the liveness claim is not a provider mutation (AC6, AC8)"
348
- require_text "$PULL" '#290' "pull-work names #290 as the deferred assignment-provider seam (AC6, AC8)"
349
- require_text "$PULL" 'liveness_preflight' "pull-work artifact contract records liveness_preflight (AC1, AC8)"
350
- require_text "$PULL" 'liveness_claim' "pull-work artifact contract records liveness_claim (AC4, AC8)"
351
- require_text "$PICKUP_PROBE" 'flags the selected item .reclaimable., treat the recorded opt-in as a decision to re-confirm' "pickup-probe re-confirms (not silently accepts) a reclaimable opt-in on drift (AC3, AC8)"
352
-
353
- # ─── F2-F6 (fix-plan iteration 1) static assertions ─────────────────────────
354
- require_text "$PULL" 'group all rows for that .subjectId. by subject' "pull-work classifies per-subject (grouped rows), not per-row (F2, AC1, AC8)"
355
- require_text "$PULL" 'classify in this precedence order' "pull-work states the classification is an ordered precedence rule (F2, AC8)"
356
- # F2's original numbered precedence list was liveness-only (#166); #290 (Wave 3) replaced it with
357
- # the full ADR 0021 §1 assignment ⋈ liveness join, computed via `assignment-provider status`'s
358
- # `effective_state`/`reason` fields. These assertions are updated to match the new five-row list
359
- # (mine/held/reclaimable/human-held/free) rather than the old four-row liveness-only list.
360
- require_text "$PULL" '^1\. .effective_state: .held.. with .reason: .self_is_holder..' "pull-work's precedence rule step 1 (mine, via self_is_holder) is numbered verbatim (F2, #290, AC8)"
361
- require_text "$PULL" '^2\. else .effective_state: .held..' "pull-work's precedence rule step 2 (held, excluded) is numbered verbatim (F2, #290, AC8)"
362
- require_text "$PULL" '^3\. else .effective_state: .reclaimable..' "pull-work's precedence rule step 3 (reclaimable) is numbered verbatim (F2, #290, AC8)"
363
- require_text "$PULL" '^4\. else .effective_state: .human-held..' "pull-work's precedence rule step 4 (human-held) is numbered verbatim (F2, #290, AC11, AC8)"
364
- require_text "$PULL" '^5\. else .effective_state: .free..' "pull-work's precedence rule step 5 (free) is numbered verbatim (F2, #290, AC8)"
365
- require_text "$PULL" 'double-hold' "pull-work names the own-actor + other-actor co-existing row combination a double-hold (F2, AC8)"
366
- require_text "$PULL" 'explicit conflict warning \(per ADR 0012 §4 detection' "pull-work cites ADR 0012 §4 detection for the double-hold conflict warning (F2, AC8)"
367
- require_text "$PULL" 'never silently resolve it to .mine.' "pull-work states a double-hold is never silently resolved to mine (F2, AC8)"
368
-
369
- require_text "$PULL" 'pin it for reuse' "pull-work pins self_actor for reuse across the pass (F3, AC8)"
370
- require_text "$PULL" 'Capture the returned .actor. value as .self_actor.' "pull-work captures self_actor exactly once per pass from whoami (F3, AC8)"
371
- require_text "$PULL" 'liveness claim <subjectId> --actor <self_actor>' "pull-work's claim-on-selection command passes --actor <self_actor> explicitly (F3, AC4, AC8)"
372
- require_text "$PULL" 'always pass .--actor <self_actor>. explicitly on every claim in this pass' "pull-work requires --actor <self_actor> on every claim in the pass, not just the first (F3, AC8)"
373
- require_text "$PULL" 'never a fresh derivation per claim call' "pull-work states the actor is never re-derived per claim call (F3, AC8)"
374
-
375
- require_text "$PULL" 'On any claim-emit failure \(non-zero exit, unresolved actor, or liveness disabled/unavailable\)' "pull-work names the precise claim-emit failure modes covered by fail-open (F4, AC8)"
376
- require_text "$PULL" '\{skipped: <stderr reason>\}' "pull-work's fail-open shape records {skipped: <stderr reason>} (F4, AC8)"
377
- require_text "$PULL" 'also surface that skip reason in pull-work.s user-facing output' "pull-work requires the skip reason to be surfaced in user-facing output, never silent (F4, AC8)"
378
- require_text "$PULL" 'unresolved-actor failure.? additionally names? the remediation' "pull-work requires unresolved-actor failures to additionally name the remediation (F4, AC8)"
379
-
380
- require_text "$PULL" '.reclaimable_override.: recorded only when a .reclaimable.' "pull-work's Artifact Contract declares the reclaimable_override field (F5, AC8)"
381
-
382
- require_text "$PULL" '### Post-Claim Conflict Re-check' "pull-work documents the Post-Claim Conflict Re-check subsection (F6, AC8)"
383
- require_text "$PULL" 'coexists with this session.s own just-emitted claim on the same subject' "pull-work's post-claim re-check detects a double-hold against the just-emitted claim (F6, AC8)"
384
- require_text "$PULL" 'surface the conflict prominently in the user-facing output and instruct the user to coordinate before proceeding' "pull-work instructs surfacing the post-claim conflict prominently and coordinating before proceeding, not silently continuing (F6, AC8)"
385
- require_text "$PULL" 'does not provide true mutual exclusion across the read-then-write race window itself' "pull-work's honesty note states the exclusion guarantee still does not provide true mutual exclusion across the read-then-write race window (F6, AC8; updated #320 wording — see also test_liveness_verdict.sh)"
386
- require_text "$PULL" '.#290.\x27s provider assignment lease closes this gap for the .{0,2}local-file.{0,2} provider only' "pull-work scopes true mutual exclusion to the local-file provider only, via #290's lock (fix-plan iteration 1, F5, AC8)"
387
- require_text "$PULL" 'two concurrent local-file .claim. calls on the same subject genuinely cannot both win' "pull-work states local-file claim/claim races genuinely cannot both win under #290's lock (fix-plan iteration 1, F5, AC8)"
388
- require_text "$PULL" 'The .{0,2}GitHub.{0,2} provider \(assignee/label/claim-comment\) remains advisory/last-writer' "pull-work does NOT overclaim true mutual exclusion for the GitHub provider — advisory/last-writer, detect not prevent (fix-plan iteration 1, F5, AC8)"
389
- require_text "$PULL" 'Do not read .provider assignment lease. as closing the GitHub race; only the .verify-hold. publish gate \(#293\)' "pull-work explicitly warns not to read #290 as closing the GitHub race — only #293's verify-hold gate would (fix-plan iteration 1, F5, AC8)"
390
-
326
+ # ─── D. Provider-neutral skill contract assertions ─────────────────────────
327
+ echo "--- D. Provider-neutral skill contract assertions ---"
328
+
329
+ require_text "$PULL" 'Assignment And Liveness Selection Preflight' "pull-work documents assignment/liveness preflight"
330
+ require_text "$PULL" 'AssignmentProvider\.status' "pull-work consumes assignment status through the provider"
331
+ require_text "$PULL" 'classify the subject, not individual observation rows' "pull-work classifies grouped subject state"
332
+ require_text "$PULL" 'in this precedence' "pull-work documents ordered ownership states"
333
+ require_text "$PULL" 'raw provider status' "pull-work consumes raw status instead of display labels"
334
+ require_text "$PULL" 'double-hold conflict' "pull-work detects own/other live conflicts"
335
+ require_text "$PULL" 'Exclude it by default' "pull-work excludes held work by default"
336
+ require_text "$PULL" 'explicit recorded opt-in' "pull-work requires explicit reclaimable takeover"
337
+ require_text "$PULL" 'reclaimable_override' "pull-work records reclaimable overrides"
338
+ require_text "$PULL" 'takeover is resumption, not restart' "pull-work preserves incumbent continuation"
339
+ require_text "$PULL" 'AssignmentProvider\.claim' "pull-work claims through the provider boundary"
340
+ require_text "$PULL" 'After .AssignmentProvider\.claim' "pull-work rechecks ownership after claim"
341
+ require_text "$PULL" 'post-claim' "pull-work records post-claim conflicts"
342
+ require_text "$PULL" 'does not imply universal mutual exclusion' "pull-work does not overclaim race prevention"
343
+ require_text "$PULL" 'local-file provider' "pull-work scopes serialized claims to capable providers"
344
+ require_text "$PULL" 'without compare-and-swap' "pull-work treats non-atomic remote providers honestly"
345
+ require_text "$PULL" 'unrelated provider state' "pull-work limits provider mutation"
346
+ require_text "$PICKUP_PROBE" 're-confirm the recorded takeover opt-in' "pickup-probe re-confirms reclaimable takeover after drift"
391
347
 
392
348
  echo ""
393
349
  if [[ "$errors" -eq 0 ]]; then
@@ -31,7 +31,11 @@ WRITER="workflow-sidecar"
31
31
  TMPDIR_EVAL="$(mktemp -d)"
32
32
  errors=0
33
33
 
34
- cleanup() { rm -rf "$TMPDIR_EVAL"; }
34
+ cleanup() {
35
+ local status=$?
36
+ rm -rf "$TMPDIR_EVAL"
37
+ return "$status"
38
+ }
35
39
  trap cleanup EXIT
36
40
 
37
41
  _pass() { echo " ✓ $1"; }
@@ -46,6 +50,7 @@ SESSION_ROOT="$TMPDIR_EVAL/repo/.kontourai/flow-agents"
46
50
  SLUG="sidecar-field-preservation-sweep"
47
51
  SESSION_DIR="$SESSION_ROOT/$SLUG"
48
52
  STATE="$SESSION_DIR/state.json"
53
+ DELIVER_ARTIFACT="$SESSION_DIR/$SLUG--deliver.md"
49
54
  mkdir -p "$SESSION_ROOT"
50
55
 
51
56
  # ─── Field-identity assertion helpers ────────────────────────────────────────
@@ -58,7 +63,11 @@ mkdir -p "$SESSION_ROOT"
58
63
  # persistent field. No fixture forces a synthetic owner value — that would test a code path that
59
64
  # does not exist today.
60
65
  FIELDS=(branch task_slug repo created_at owner)
61
- declare -A BASELINE
66
+ BASELINE_BRANCH=""
67
+ BASELINE_TASK_SLUG=""
68
+ BASELINE_REPO=""
69
+ BASELINE_CREATED_AT=""
70
+ BASELINE_OWNER=""
62
71
 
63
72
  _field() {
64
73
  local file="$1" field="$2"
@@ -66,19 +75,32 @@ _field() {
66
75
  }
67
76
 
68
77
  _capture_baseline() {
69
- local field
70
- for field in "${FIELDS[@]}"; do
71
- BASELINE["$field"]="$(_field "$STATE" "$field")"
72
- done
78
+ BASELINE_BRANCH="$(_field "$STATE" branch)"
79
+ BASELINE_TASK_SLUG="$(_field "$STATE" task_slug)"
80
+ BASELINE_REPO="$(_field "$STATE" repo)"
81
+ BASELINE_CREATED_AT="$(_field "$STATE" created_at)"
82
+ BASELINE_OWNER="$(_field "$STATE" owner)"
83
+ }
84
+
85
+ _baseline_field() {
86
+ case "$1" in
87
+ branch) printf '%s' "$BASELINE_BRANCH" ;;
88
+ task_slug) printf '%s' "$BASELINE_TASK_SLUG" ;;
89
+ repo) printf '%s' "$BASELINE_REPO" ;;
90
+ created_at) printf '%s' "$BASELINE_CREATED_AT" ;;
91
+ owner) printf '%s' "$BASELINE_OWNER" ;;
92
+ *) return 1 ;;
93
+ esac
73
94
  }
74
95
 
75
96
  _assert_preserved() {
76
97
  local label="$1"
77
- local field actual ok=1
98
+ local field actual expected ok=1
78
99
  for field in "${FIELDS[@]}"; do
79
100
  actual="$(_field "$STATE" "$field")"
80
- if [[ "$actual" != "${BASELINE[$field]}" ]]; then
81
- _fail "$label dropped/changed persistent field '$field': expected '${BASELINE[$field]}' got '$actual'"
101
+ expected="$(_baseline_field "$field")"
102
+ if [[ "$actual" != "$expected" ]]; then
103
+ _fail "$label dropped/changed persistent field '$field': expected '$expected' got '$actual'"
82
104
  ok=0
83
105
  fi
84
106
  done
@@ -113,8 +135,8 @@ if [[ ! -f "$STATE" ]]; then
113
135
  fi
114
136
 
115
137
  _capture_baseline
116
- if [[ "${BASELINE[branch]}" != "agent/sweep-actor/$SLUG" || "${BASELINE[created_at]}" != "$SEED_TS" || "${BASELINE[task_slug]}" != "$SLUG" ]]; then
117
- _fail "sweep setup: seeded baseline did not carry the expected branch/created_at/task_slug (branch=${BASELINE[branch]} created_at=${BASELINE[created_at]} task_slug=${BASELINE[task_slug]})"
138
+ if [[ "$BASELINE_BRANCH" != "agent/sweep-actor/$SLUG" || "$BASELINE_CREATED_AT" != "$SEED_TS" || "$BASELINE_TASK_SLUG" != "$SLUG" ]]; then
139
+ _fail "sweep setup: seeded baseline did not carry the expected branch/created_at/task_slug (branch=$BASELINE_BRANCH created_at=$BASELINE_CREATED_AT task_slug=$BASELINE_TASK_SLUG)"
118
140
  fi
119
141
 
120
142
  # ─── 1. init-plan, run against a BRANCH-LESS plan artifact ───────────────────────────────────
@@ -194,6 +216,8 @@ if flow_agents_node "$WRITER" record-critique "$SESSION_DIR" \
194
216
  --reviewer tool-code-reviewer \
195
217
  --verdict pass \
196
218
  --summary "No blocking findings." \
219
+ --artifact-ref "$PLAN_ARTIFACT" \
220
+ --lane-json "{\"id\":\"code-review\",\"status\":\"pass\",\"summary\":\"Reviewed the field-preservation plan artifact.\",\"evidence_refs\":[{\"kind\":\"artifact\",\"file\":\"$PLAN_ARTIFACT\",\"summary\":\"Reviewed field-preservation plan artifact.\"}]}" \
197
221
  --finding-json '{"id":"sweep-finding","severity":"low","status":"fixed","description":"No blocking issues found during sweep sanity critique."}' \
198
222
  --timestamp "2026-06-20T08:25:00Z" >"$TMPDIR_EVAL/critique.out" 2>"$TMPDIR_EVAL/critique.err"; then
199
223
  _assert_preserved "record-critique"
@@ -211,6 +235,7 @@ fi
211
235
  if flow_agents_node "$WRITER" record-gate-claim "$SESSION_DIR" \
212
236
  --status pass \
213
237
  --summary "Implementation scope recorded for the sweep fixture." \
238
+ --evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$DELIVER_ARTIFACT\",\"summary\":\"Durable delivery artifact for the field-preservation implementation scope.\"}" \
214
239
  --timestamp "2026-06-20T08:30:00Z" >"$TMPDIR_EVAL/gate-claim.out" 2>"$TMPDIR_EVAL/gate-claim.err"; then
215
240
  _assert_preserved "record-gate-claim"
216
241
  else