crewly 1.20.349 → 1.20.351

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 (70) hide show
  1. package/config/skills/agent/core/complete-task/SKILL.md +6 -5
  2. package/config/skills/agent/core/complete-task/execute.sh +13 -4
  3. package/config/skills/agent/core/complete-task/execute.test.sh +7 -0
  4. package/config/skills/agent/core/report-status/SKILL.md +3 -3
  5. package/config/skills/agent/core/report-status/execute.sh +9 -5
  6. package/config/skills/agent/core/trace-read/SKILL.md +14 -0
  7. package/config/skills/agent/core/trace-read/execute.sh +25 -2
  8. package/config/skills/orchestrator/complete-task/SKILL.md +1 -1
  9. package/config/skills/orchestrator/complete-task/execute.sh +3 -2
  10. package/config/skills/orchestrator/render-verdict/SKILL.md +2 -1
  11. package/config/skills/orchestrator/render-verdict/execute.sh +8 -4
  12. package/config/skills/team-leader/verify-output/SKILL.md +8 -3
  13. package/config/skills/team-leader/verify-output/execute.sh +4 -3
  14. package/config/skills/team-leader/verify-output/execute.test.sh +2 -0
  15. package/dist/backend/backend/src/constants.d.ts +30 -5
  16. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  17. package/dist/backend/backend/src/constants.js +32 -5
  18. package/dist/backend/backend/src/constants.js.map +1 -1
  19. package/dist/backend/backend/src/controllers/request/request.controller.d.ts +12 -0
  20. package/dist/backend/backend/src/controllers/request/request.controller.d.ts.map +1 -1
  21. package/dist/backend/backend/src/controllers/request/request.controller.js +48 -0
  22. package/dist/backend/backend/src/controllers/request/request.controller.js.map +1 -1
  23. package/dist/backend/backend/src/controllers/request/request.routes.d.ts +1 -0
  24. package/dist/backend/backend/src/controllers/request/request.routes.d.ts.map +1 -1
  25. package/dist/backend/backend/src/controllers/request/request.routes.js +4 -1
  26. package/dist/backend/backend/src/controllers/request/request.routes.js.map +1 -1
  27. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts +8 -5
  28. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts.map +1 -1
  29. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js +91 -16
  30. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js.map +1 -1
  31. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.d.ts.map +1 -1
  32. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js +3 -1
  33. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js.map +1 -1
  34. package/dist/backend/backend/src/services/messaging/agent-ask-ledger.service.d.ts +6 -0
  35. package/dist/backend/backend/src/services/messaging/agent-ask-ledger.service.d.ts.map +1 -1
  36. package/dist/backend/backend/src/services/messaging/agent-ask-ledger.service.js +9 -0
  37. package/dist/backend/backend/src/services/messaging/agent-ask-ledger.service.js.map +1 -1
  38. package/dist/backend/backend/src/services/task-pool/completion-evidence.service.d.ts +74 -5
  39. package/dist/backend/backend/src/services/task-pool/completion-evidence.service.d.ts.map +1 -1
  40. package/dist/backend/backend/src/services/task-pool/completion-evidence.service.js +187 -21
  41. package/dist/backend/backend/src/services/task-pool/completion-evidence.service.js.map +1 -1
  42. package/dist/backend/backend/src/services/v3/request-whereabouts.service.d.ts +88 -0
  43. package/dist/backend/backend/src/services/v3/request-whereabouts.service.d.ts.map +1 -0
  44. package/dist/backend/backend/src/services/v3/request-whereabouts.service.js +193 -0
  45. package/dist/backend/backend/src/services/v3/request-whereabouts.service.js.map +1 -0
  46. package/dist/backend/backend/src/types/v2/completion-evidence.types.d.ts +16 -0
  47. package/dist/backend/backend/src/types/v2/completion-evidence.types.d.ts.map +1 -1
  48. package/dist/backend/backend/src/types/v2/completion-evidence.types.js.map +1 -1
  49. package/dist/backend/backend/src/types/v2/work-item.types.d.ts +6 -0
  50. package/dist/backend/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  51. package/dist/backend/backend/src/types/v2/work-item.types.js +6 -0
  52. package/dist/backend/backend/src/types/v2/work-item.types.js.map +1 -1
  53. package/dist/backend/build-info.json +2 -2
  54. package/dist/cli/backend/src/constants.d.ts +30 -5
  55. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  56. package/dist/cli/backend/src/constants.js +32 -5
  57. package/dist/cli/backend/src/constants.js.map +1 -1
  58. package/dist/cli/backend/src/services/messaging/agent-ask-ledger.service.d.ts +6 -0
  59. package/dist/cli/backend/src/services/messaging/agent-ask-ledger.service.d.ts.map +1 -1
  60. package/dist/cli/backend/src/services/messaging/agent-ask-ledger.service.js +9 -0
  61. package/dist/cli/backend/src/services/messaging/agent-ask-ledger.service.js.map +1 -1
  62. package/dist/cli/backend/src/types/v2/work-item.types.d.ts +6 -0
  63. package/dist/cli/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  64. package/dist/cli/backend/src/types/v2/work-item.types.js +6 -0
  65. package/dist/cli/backend/src/types/v2/work-item.types.js.map +1 -1
  66. package/frontend/dist/assets/{index-36b1788c.js → index-b1fc60ea.js} +65 -65
  67. package/frontend/dist/index.html +1 -1
  68. package/package.json +1 -1
  69. package/packages/crewly-agent/src/runtime/tool-registry.test.ts +26 -0
  70. package/packages/crewly-agent/src/runtime/tool-registry.ts +31 -4
@@ -46,12 +46,12 @@ Mark a task as complete with a summary of the work done. If the task has an outp
46
46
  | `workItemId` | Preferred | ID of the V3 WorkItem to complete. This is the only input that selects the WorkItem |
47
47
  | `sessionName` | Yes | Your agent session name |
48
48
  | `summary` | Yes | Summary of the work completed |
49
- | `evidence` | Yes* | Array of evidence entries — see **Evidence contract** below. *Accepted without it this release (with a warning); required from the next release |
49
+ | `evidence` | Yes* | Array of evidence entries — see **Evidence contract** below. *Required: refused without it (400 `evidence_required`), except a review `verdict` |
50
50
  | `absoluteTaskPath` | No | **Legacy (V1).** Still accepted so older callers keep working, but it does NOT identify a WorkItem |
51
51
  | `output` | No | Structured output object (required if task has an output schema) |
52
52
  | ~~`skipGates`~~ | **Rejected** | **Not supported.** This endpoint runs no quality gates, so there is nothing to skip. Passing it is a hard error. Use the `check-quality-gates` skill for gates. |
53
53
 
54
- **Any other field is an error.** The skill accepts only the fields in this table plus `verdict`/`feedback` (reviews) and `taskId`/`artifacts`/`testResults`/`structured` (verification requests). An unknown field (for example `projectPath`, `skipGates`, `force`) stops the call before anything is sent, and the error names the field. Put extra results inside `output`.
54
+ **Any other field is an error.** The skill accepts only the fields in this table plus `verdict`/`feedback`/`checks` (reviews) and `taskId`/`artifacts`/`testResults`/`structured` (verification requests). An unknown field (for example `projectPath`, `skipGates`, `force`) stops the call before anything is sent, and the error names the field. Put extra results inside `output`.
55
55
 
56
56
  On success the skill prints **one JSON line** that always names the `workItemId`, plus the server's reply (`success`, `message`, any `warning`).
57
57
 
@@ -83,8 +83,8 @@ items for one session.
83
83
 
84
84
  If you could not finish, do **not** report done: send a `blocked` entry (or use
85
85
  `report-status --status blocked`). Malformed evidence is rejected with 400
86
- naming the bad entry. A completion with no evidence is accepted this release
87
- but the response (and stderr) carries a `warning`; next release it is a 400.
86
+ naming the bad entry. A completion with no evidence is refused with 400
87
+ `evidence_required` and nothing is completed (#1312).
88
88
  A review verdict (`verdict` set) needs no evidence.
89
89
 
90
90
  ## Example
@@ -154,9 +154,10 @@ JSON confirmation of task completion status. If validation fails:
154
154
 
155
155
  When the item you're completing is a review of another agent's work:
156
156
 
157
- - **Accept:** complete it normally with a summary.
157
+ - **Accept:** open or re-run the worker's evidence (the item lists it numbered; `verify-output` shows it in full) and send `"verdict":"verified"` with `"checks"`: one `{"entry":<index>,"did":"<what you did and saw>","outcome":"pass"}` per entry you checked, `"entry":null` for a direct look at the work. At least one check must name a worker evidence entry when there is any. An accept without checks, or with a `"fail"` check, is refused (400 `review_unchecked` / `review_check_failed`) and nothing is accepted.
158
158
  - **Send it back:** add `"verdict":"rejected"` and `"feedback":"<what is wrong>"`. The worker gets a retry that includes your feedback. Feedback is required when you reject.
159
159
 
160
160
  ```bash
161
+ bash execute.sh '{"workItemId":"<verify item id>","sessionName":"<you>","summary":"Export is right","verdict":"verified","checks":[{"entry":0,"did":"opened export.csv: 120 rows, header present","outcome":"pass"},{"entry":1,"did":"re-ran npm test: exit 0","outcome":"pass"}]}'
161
162
  bash execute.sh '{"workItemId":"<verify item id>","sessionName":"<you>","summary":"Header row missing","verdict":"rejected","feedback":"Add the header row and re-run the export"}'
162
163
  ```
@@ -35,7 +35,7 @@ SUMMARY=$(printf '%s' "$INPUT" | jq -r '.summary // empty')
35
35
  # ignoring a field is the worst disposition: the caller believes it did
36
36
  # something, and nothing ever fails. So every field this skill does not use
37
37
  # fails loudly, with its name, before any request is sent.
38
- ALLOWED_FIELDS='["workItemId","absoluteTaskPath","sessionName","summary","output","evidence","verdict","feedback","taskId","artifacts","testResults","structured"]'
38
+ ALLOWED_FIELDS='["workItemId","absoluteTaskPath","sessionName","summary","output","evidence","verdict","feedback","checks","taskId","artifacts","testResults","structured"]'
39
39
  SKIP_GATES=$(printf '%s' "$INPUT" | jq -r 'has("skipGates")')
40
40
  if [ "$SKIP_GATES" = "true" ]; then
41
41
  error_exit "skipGates is not supported by complete-task and never was — it was accepted and silently discarded. POST /task-pool/complete runs no quality gates, so there is nothing here to skip. Quality gates live behind the 'check-quality-gates' skill (POST /quality-gates/check); run or skip them there. Remove skipGates from this call."
@@ -67,6 +67,13 @@ fi
67
67
  if [ "$VERDICT" = "rejected" ] && [ -z "$FEEDBACK" ]; then
68
68
  error_exit "verdict \"rejected\" needs feedback: say what is wrong so the retry can fix it"
69
69
  fi
70
+ # Accepting a review records what you checked, per worker evidence entry
71
+ # (#1314): [{"entry":<index or null>,"did":"<what you did and saw>","outcome":"pass"|"fail"}].
72
+ # The server refuses an accept without it; this only catches a non-array.
73
+ CHECKS_JSON=$(printf '%s' "$INPUT" | jq -c '.checks // empty')
74
+ if [ -n "$CHECKS_JSON" ] && [ "$(printf '%s' "$CHECKS_JSON" | jq -r 'type')" != "array" ]; then
75
+ error_exit "checks must be a JSON array, e.g. [{\"entry\":0,\"did\":\"opened report.md: covers all 3 asks\",\"outcome\":\"pass\"}]"
76
+ fi
70
77
  require_param "sessionName" "$SESSION_NAME"
71
78
  require_param "summary" "$SUMMARY"
72
79
 
@@ -167,6 +174,7 @@ BODY=$(jq -n \
167
174
  --arg verdict "$VERDICT" \
168
175
  --arg feedback "$FEEDBACK" \
169
176
  --argjson evidence "${EVIDENCE_JSON:-null}" \
177
+ --argjson checks "${CHECKS_JSON:-null}" \
170
178
  '{
171
179
  agentId: $agentId,
172
180
  result: ({summary: $summary}
@@ -175,7 +183,8 @@ BODY=$(jq -n \
175
183
  else {} end)
176
184
  + (if $verdict != "" then {verdict: $verdict} else {} end)
177
185
  + (if $feedback != "" then {feedback: $feedback} else {} end)
178
- + (if $evidence != null then {evidence: $evidence} else {} end))
186
+ + (if $evidence != null then {evidence: $evidence} else {} end)
187
+ + (if $checks != null then {checks: $checks} else {} end))
179
188
  }')
180
189
 
181
190
  COMPLETE_RESPONSE=$(api_call POST "/task-pool/complete/${WORK_ITEM_ID}" "$BODY")
@@ -191,8 +200,8 @@ if [ -z "$RESULT_LINE" ]; then
191
200
  '{success: true, workItemId: $id, message: ("WorkItem " + $id + " completion was accepted; the server reply was not JSON."), raw: $raw}')
192
201
  fi
193
202
  printf '%s\n' "$RESULT_LINE"
194
- # Warn-mode rollout (#873): the server accepts a completion without evidence
195
- # for one release but says so. Repeat it on stderr so it is not missed.
203
+ # With CREWLY_EVIDENCE_MODE=warn the server accepts a completion without
204
+ # evidence but says so (#873, #1312). Repeat it on stderr so it is not missed.
196
205
  EVIDENCE_WARNING=$(printf '%s' "$COMPLETE_RESPONSE" | jq -r '.warning // empty' 2>/dev/null || true)
197
206
  if [ -n "$EVIDENCE_WARNING" ]; then
198
207
  jq -n --arg w "$EVIDENCE_WARNING" '{warning: $w}' >&2
@@ -224,6 +224,13 @@ assert_not_contains "no request sent without feedback" "/task-pool/complete" "$R
224
224
  run_skill '{"workItemId":"wi-verify","sessionName":"tl-1","summary":"x","verdict":"maybe"}'
225
225
  assert_contains "unknown verdict is refused" "verdict must be" "$OUT"
226
226
 
227
+ run_skill '{"workItemId":"wi-verify","sessionName":"tl-1","summary":"ok","verdict":"verified","checks":[{"entry":0,"did":"opened it","outcome":"pass"}]}'
228
+ CHECKS_BODY="$(printf '%s' "$BODIES" | grep 'agentId' | head -1 || true)"
229
+ assert_contains "checks land in result (#1314)" '"did": "opened it"' "$CHECKS_BODY"
230
+
231
+ run_skill '{"workItemId":"wi-verify","sessionName":"tl-1","summary":"ok","verdict":"verified","checks":"looked at it"}'
232
+ assert_contains "non-array checks are refused" "checks must be a JSON array" "$OUT"
233
+
227
234
  run_skill '{"workItemId":"wi-plain","sessionName":"dev-1","summary":"done"}'
228
235
  PLAIN_BODY="$(printf '%s' "$BODIES" | grep 'agentId' | head -1 || true)"
229
236
  assert_not_contains "no verdict key when none given" '"verdict"' "$PLAIN_BODY"
@@ -74,9 +74,9 @@ For a bug fix, the failing "before" run belongs in the evidence too: put it in t
74
74
 
75
75
  The server rejects (400) a missing artifact, a non-zero exit code, or a
76
76
  malformed entry; the skill then prints `{"warning":"… completing the WorkItem
77
- FAILED …","error":…}` with the reason. Without any evidence, `done` is accepted
78
- **this release** with a `warning` on stderr; from the next release it is
79
- refused. If you could not finish, report `--status blocked` (or `done` with
77
+ FAILED …","error":…}` with the reason. Without any evidence, `done` is
78
+ **refused** (400 `evidence_required`) and the WorkItem stays open; the skill
79
+ prints a `next` line with the flags to add. If you could not finish, report `--status blocked` (or `done` with
80
80
  `--blocked-step/--blocked-reason`), never `done`.
81
81
 
82
82
  ## This skill COMPLETES a WorkItem, not just reports
@@ -53,7 +53,7 @@ Evidence (status done — #873: "done" needs evidence):
53
53
  --blocked-reason <why> ... and why. The WorkItem is recorded as BLOCKED, not done.
54
54
  --evidence <json> Raw evidence array, e.g. '[{"type":"artifact","path":"/abs/f"}]'
55
55
  A non-zero --exit-code or a missing artifact is rejected by the server. Without
56
- any evidence, done is accepted this release with a warning; next release it is refused.
56
+ any evidence, done is refused and the WorkItem stays open (#1312).
57
57
  --help | -h Show this help
58
58
  EOF_USAGE
59
59
  }
@@ -385,8 +385,8 @@ if [ "$STATUS" = "done" ]; then
385
385
  # `agentId is required` + `summary required in body.result`,
386
386
  # forcing every worker into a direct-curl workaround.
387
387
  #
388
- # #873: the evidence block goes in result.evidence. Omitted when empty
389
- # (the server then warns this release, refuses the next).
388
+ # #873: the evidence block goes in result.evidence. Omitted when empty;
389
+ # the server then refuses a deliverable's completion (#1312).
390
390
  COMPLETE_BODY=$(jq -n \
391
391
  --arg agentId "$SESSION_NAME" \
392
392
  --arg summary "$SUMMARY" \
@@ -410,8 +410,12 @@ if [ "$STATUS" = "done" ]; then
410
410
  '{completedWorkItem: $id, resolvedBy: $how} + (if $w != "" then {warning: $w} else {} end)' >&2
411
411
  fi
412
412
  else
413
- jq -n --arg id "$TARGET_WI_ID" --arg err "$COMPLETE_RESULT" \
414
- '{warning: "status reported, but completing the WorkItem FAILED — it is still open", workItemId: $id, error: $err}' >&2
413
+ NEXT_STEP=""
414
+ case "$COMPLETE_RESULT" in
415
+ *evidence_required*) NEXT_STEP="Run report-status --status done again with evidence: --artifact <file or https URL> (repeatable) and/or --command '<cmd>' --exit-code N; if you could not finish, --blocked-step '<step>' --blocked-reason '<why>'." ;;
416
+ esac
417
+ jq -n --arg id "$TARGET_WI_ID" --arg err "$COMPLETE_RESULT" --arg next "$NEXT_STEP" \
418
+ '{warning: "status reported, but completing the WorkItem FAILED — it is still open", workItemId: $id, error: $err} + (if $next != "" then {next: $next} else {} end)' >&2
415
419
  fi
416
420
  fi
417
421
  fi
@@ -27,6 +27,8 @@ triggers:
27
27
  - how did the run go
28
28
  - what happened to my work
29
29
  - why was it stuck
30
+ - where is it now
31
+ - who has it
30
32
  - stalls
31
33
  - retro
32
34
  - autonomy
@@ -87,6 +89,18 @@ You get, in at most `--max-chars` (default 4000):
87
89
  counted).
88
90
  - **Links** — the dashboard page with its Timeline tab, and the API.
89
91
 
92
+ ## Where a request is now
93
+
94
+ ```bash
95
+ bash execute.sh --where TKT-12 # or the request id
96
+ ```
97
+
98
+ Who holds the owner's request right now, what they are doing (working,
99
+ queued, blocked, reviewing, waiting on another agent, waiting on the owner)
100
+ and for how long. It follows plain-message hand-offs too: if Ella passed it
101
+ to Pia and Pia to Dex, you see all three and that Dex has it. Use this when
102
+ the owner asks "how is X going" or "is it forgotten", before guessing.
103
+
90
104
  ## Recent runs
91
105
 
92
106
  ```bash
@@ -10,6 +10,7 @@
10
10
  # bash execute.sh --trace tr-20261003-ab12cd34
11
11
  # bash execute.sh --work-item <id> | --ticket CE-7 | --ticket TKT-12 | --request <id> | --experiment EXP-3
12
12
  # bash execute.sh --since 2026-10-01T00:00:00Z [--limit 10] # recent runs, one line each
13
+ # bash execute.sh --where TKT-12 | --where <request id> # who holds it NOW, doing what, since when
13
14
  # Options: [--max-chars 4000] [--stall-minutes 30] [--json]
14
15
  # =============================================================================
15
16
  set -euo pipefail
@@ -25,6 +26,7 @@ Usage:
25
26
  bash execute.sh --request ID The run of a Request
26
27
  bash execute.sh --experiment EXP-3 The run of an experiment card
27
28
  bash execute.sh --since ISO [--limit 10] Runs active since then, one line each, newest first (at most 100)
29
+ bash execute.sh --where TKT-12 | --where ID Where an owner request is NOW: who holds it, doing what, for how long
28
30
  Options:
29
31
  --max-chars N Size bound of the output (default 4000, 600..16000)
30
32
  --stall-minutes N A gap with no progress longer than this is a stall (default 30)
@@ -32,10 +34,11 @@ Options:
32
34
  EOF_USAGE
33
35
  }
34
36
 
35
- TRACE=""; WORK_ITEM=""; TICKET=""; REQUEST=""; EXPERIMENT=""; SINCE=""; LIMIT="10"; MAX_CHARS="4000"; STALL=""; JSON_OUT="0"
37
+ WHERE=""; TRACE=""; WORK_ITEM=""; TICKET=""; REQUEST=""; EXPERIMENT=""; SINCE=""; LIMIT="10"; MAX_CHARS="4000"; STALL=""; JSON_OUT="0"
36
38
 
37
39
  while [[ $# -gt 0 ]]; do
38
40
  case "$1" in
41
+ --where) [ $# -ge 2 ] || error_exit "--where requires a request id or TKT-n"; WHERE="$2"; shift 2 ;;
39
42
  --trace|-t) [ $# -ge 2 ] || error_exit "--trace requires a value"; TRACE="$2"; shift 2 ;;
40
43
  --work-item|-w) [ $# -ge 2 ] || error_exit "--work-item requires a value"; WORK_ITEM="$2"; shift 2 ;;
41
44
  --ticket) [ $# -ge 2 ] || error_exit "--ticket requires a value"; TICKET="$2"; shift 2 ;;
@@ -65,9 +68,29 @@ enc() { jq -rn --arg v "$1" '$v|@uri'; }
65
68
  STALL_QS=""
66
69
  [ -n "$STALL" ] && STALL_QS="&stallMinutes=$(enc "$STALL")"
67
70
 
71
+ # --- Where a request is now (backed by GET /api/requests/:id/whereabouts) ---
72
+ if [ -n "$WHERE" ]; then
73
+ if ! RESP=$(api_call_full GET "/requests/$(enc "$WHERE")/whereabouts"); then
74
+ error_exit "No owner request $WHERE (pass a request id or TKT-n)"
75
+ fi
76
+ if [ "$JSON_OUT" = "1" ]; then
77
+ printf '%s' "$RESP" | jq -c '{success: true} + .data'
78
+ exit 0
79
+ fi
80
+ printf '%s' "$RESP" | jq -r --argjson max "$MAX_CHARS" '
81
+ def dur: (. / 60000 | floor) as $m
82
+ | if $m < 60 then "\($m)m" elif $m < 2880 then "\($m / 60 | floor)h \($m % 60)m" else "\($m / 1440 | floor)d \(($m % 1440) / 60 | floor)h" end;
83
+ .data as $d
84
+ | ([ "\(if $d.ticketNumber then "TKT-\($d.ticketNumber) · " else "" end)\($d.title[0:100]) · \($d.status)", $d.summary ]
85
+ + [ $d.holders[] | "- \(.session): \(.state | gsub("_"; " ")) for \(.forMs | dur) (since \(.since[0:16] | sub("T"; " ")))\(if .workItemId then " · \(.workItemId)" else "" end)\(if .from then " · from \(.from)" else "" end)\(if .blockedReason then " · blocked: \(.blockedReason[0:120])" else "" end)\(if .what then " · \(.what[0:100])" else "" end)" ]
86
+ | join("\n")) as $text
87
+ | if ($text | length) > $max then $text[0:($max - 1)] + "…" else $text end'
88
+ exit 0
89
+ fi
90
+
68
91
  # --- Recent runs -------------------------------------------------------------
69
92
  if [ -z "$TRACE$WORK_ITEM$TICKET$REQUEST$EXPERIMENT" ]; then
70
- [ -n "$SINCE" ] || { print_usage >&2; error_exit "Pass one of --trace, --work-item, --ticket, --request, --experiment or --since"; }
93
+ [ -n "$SINCE" ] || { print_usage >&2; error_exit "Pass one of --where, --trace, --work-item, --ticket, --request, --experiment or --since"; }
71
94
  if ! RESP=$(api_call_full GET "/traces?since=$(enc "$SINCE")&limit=$(enc "$LIMIT")${STALL_QS}"); then
72
95
  error_exit "Could not list traces since $SINCE"
73
96
  fi
@@ -38,7 +38,7 @@ bash config/skills/orchestrator/complete-task/execute.sh '{"workItemId":"wi-123"
38
38
  |-----------|----------|-------------|
39
39
  | `workItemId` (alias `taskId`) | Yes | The WorkItem to complete |
40
40
  | `summary` (alias `result`) | Yes | What was produced |
41
- | `evidence` | Yes* | Evidence array (#873): `{"type":"artifact","path":…}` (must exist, or an https URL), `{"type":"command","command":…,"exitCode":0,"outputTail":…}`, or `{"type":"blocked","step":…,"reason":…}` (records the item as blocked, not done). *Accepted without it this release with a `warning`; required from the next |
41
+ | `evidence` | Yes* | Evidence array (#873): `{"type":"artifact","path":…}` (must exist, or an https URL), `{"type":"command","command":…,"exitCode":0,"outputTail":…}`, or `{"type":"blocked","step":…,"reason":…}` (records the item as blocked, not done). *Required for delegate/project_task/review items (400 `evidence_required` without it); bookkeeping types (triage, replans, retros) may omit it |
42
42
  | `output` | No | Structured output stored on the WorkItem before completion |
43
43
  | `agentId` / `sessionName` | No | Who completed it (defaults to `crewly-orc`) |
44
44
 
@@ -13,8 +13,9 @@
13
13
  #
14
14
  # `evidence` (#873) is sent as result.evidence. The server checks it: missing
15
15
  # artifacts and non-zero exit codes are refused, a `blocked` entry records the
16
- # item as blocked instead of done, and no evidence at all is accepted this
17
- # release with a `warning` (refused from the next).
16
+ # item as blocked instead of done, and no evidence at all is refused for a
17
+ # deliverable (delegate, project_task, review without a verdict). Bookkeeping
18
+ # types (triage, replans, retros) complete without it (#1312).
18
19
  #
19
20
  # Backwards-compat: a `taskId` field is accepted as alias for `workItemId`.
20
21
 
@@ -45,7 +45,7 @@ orchestrator) and the backend recognizes the caller correctly.
45
45
 
46
46
  ```bash
47
47
  CREWLY_SESSION_NAME=crewly-orc bash config/skills/orchestrator/render-verdict/execute.sh \
48
- '{"workItemId":"abc-123","verdict":"verified","comment":"Meets the acceptance criteria"}'
48
+ '{"workItemId":"abc-123","verdict":"verified","comment":"Meets the acceptance criteria","checks":[{"entry":0,"did":"opened report.md: covers the 3 asks","outcome":"pass"}]}'
49
49
  ```
50
50
 
51
51
  ## Parameters
@@ -53,6 +53,7 @@ CREWLY_SESSION_NAME=crewly-orc bash config/skills/orchestrator/render-verdict/ex
53
53
  - `workItemId` (required, alias `taskId`) — the `done_by_worker` WorkItem to verdict.
54
54
  - `verdict` (required) — `"verified"` or `"rejected"`.
55
55
  - `comment` (optional) — reviewer's note; required in practice for a rejection so the worker knows what to fix.
56
+ - `checks` (required for `verified`, #1314) — what you checked: `[{"entry":<index in the item's output.evidence, or null for a direct look>,"did":"<what you did and saw>","outcome":"pass"|"fail"}]`. At least one must name an evidence entry when the worker sent any. Without it (or with a `fail`) the server returns 400 `review_unchecked` / `review_check_failed` and nothing is verified.
56
57
 
57
58
  ## Output
58
59
 
@@ -38,10 +38,14 @@ if [ "$VERDICT" != "verified" ] && [ "$VERDICT" != "rejected" ]; then
38
38
  error_exit "verdict must be \"verified\" or \"rejected\" (got: \"${VERDICT}\")"
39
39
  fi
40
40
 
41
- if [ -n "$COMMENT" ]; then
42
- BODY=$(jq -n --arg verdict "$VERDICT" --arg comment "$COMMENT" '{verdict: $verdict, comment: $comment}')
43
- else
44
- BODY=$(jq -n --arg verdict "$VERDICT" '{verdict: $verdict}')
41
+ # An accept records what you checked (#1314): the server refuses
42
+ # "verified" without checks.
43
+ CHECKS=$(printf '%s' "$INPUT" | jq -c '.checks // empty')
44
+ if [ -n "$CHECKS" ] && [ "$(printf '%s' "$CHECKS" | jq -r 'type')" != "array" ]; then
45
+ error_exit "checks must be a JSON array, e.g. [{\"entry\":0,\"did\":\"opened report.md: covers the 3 asks\",\"outcome\":\"pass\"}]"
45
46
  fi
46
47
 
48
+ BODY=$(jq -n --arg verdict "$VERDICT" --arg comment "$COMMENT" --argjson checks "${CHECKS:-null}" \
49
+ '{verdict: $verdict} + (if $comment != "" then {comment: $comment} else {} end) + (if $checks != null then {checks: $checks} else {} end)')
50
+
47
51
  api_call POST "/task-pool/items/${WORK_ITEM_ID}/verdict" "$BODY"
@@ -40,10 +40,13 @@ WorkItem: artifacts that exist, commands with exit codes, blocked steps) before
40
40
  running any check, and returns it as the first field of the verdict.
41
41
 
42
42
  - `evidenceWarning` is set when the item was marked done **without evidence**
43
- (accepted only while the server is in evidence warn mode) — do not verify it
43
+ (possible only with `CREWLY_EVIDENCE_MODE=warn` or before #1312) — do not verify it
44
44
  on its summary alone: check the work directly or send it back asking for
45
45
  evidence. It is also set when the worker reported `blocked` steps.
46
46
  - The warning, when present, leads `feedback`.
47
+ - Each evidence entry is listed with its index. When you accept, record what
48
+ you did to each one you checked (#1314): open the artifact, re-run the
49
+ command, look at the page. An accept without that record is refused.
47
50
 
48
51
  ## When to Use
49
52
 
@@ -162,8 +165,10 @@ requiresReview: true → TL must manually evaluate these steps
162
165
  ### Accept finished work; never cancel it
163
166
 
164
167
  When the work is done and checks pass, ACCEPT it: complete the item (for a
165
- "Verify: ..." item, `complete-task` with `"verdict":"verified"` and your
166
- evidence). Do not cancel a WorkItem that was done or verified, even with a
168
+ "Verify: ..." item, `complete-task` with `"verdict":"verified"` and
169
+ `"checks":[{"entry":<evidence index, or null for a direct look>,"did":"<what you did and saw>","outcome":"pass"}]`,
170
+ at least one naming a worker evidence entry when there is any). A failed
171
+ check cannot be accepted: send it back with `"verdict":"rejected"`. Do not cancel a WorkItem that was done or verified, even with a
167
172
  "verified" note: a cancel is for work that should not happen, and a project
168
173
  ticket whose WorkItem is cancelled can go back to the queue so the same work
169
174
  is picked up twice. Cancel only work that is NOT done.
@@ -39,8 +39,8 @@ WI_OUTPUT_RAW=$(echo "$WI_DATA" | jq -c '.data.output // empty' 2>/dev/null || t
39
39
  # Evidence first (#873). The worker's completion carries an evidence block
40
40
  # (artifacts that exist, commands with exit codes, or blocked steps), stored
41
41
  # at output.evidence. Read it before anything else, and flag an item that was
42
- # marked done WITHOUT evidence — accepted only because the server is in warn
43
- # mode this release — so it is not verified on its summary alone.
42
+ # marked done WITHOUT evidence — possible only with CREWLY_EVIDENCE_MODE=warn
43
+ # or on an item completed before #1312 — so it is not verified on its summary alone.
44
44
  WI_FOUND=$(echo "$WI_DATA" | jq -r 'if (.data // null) != null then "yes" else "no" end' 2>/dev/null || echo "no")
45
45
  WI_EVIDENCE=$(echo "$WI_DATA" | jq -c 'if (.data.output.evidence | type) == "array" then .data.output.evidence else [] end' 2>/dev/null || echo '[]')
46
46
  EVIDENCE_WARNING=""
@@ -359,7 +359,8 @@ jq -n \
359
359
  --arg workerId "$WORKER_ID" \
360
360
  --arg templateId "$TEMPLATE_ID" \
361
361
  '{
362
- evidence: $evidence,
362
+ evidence: ($evidence | to_entries | map(.value + {index: .key})),
363
+ acceptWith: "complete-task with \"verdict\":\"verified\" and \"checks\":[{\"entry\":<evidence index, or null for a direct look>,\"did\":\"<what you did and saw>\",\"outcome\":\"pass\"}] (#1314)",
363
364
  evidenceWarning: (if $evidenceWarning != "" then $evidenceWarning else null end),
364
365
  passed: ($passed == "true"),
365
366
  score: ($score | tonumber),
@@ -126,6 +126,8 @@ echo "verify-output: evidence first (#873)"
126
126
 
127
127
  assert_json_field "evidence is the first key of the verdict" \
128
128
  '{"workItemId":"wi-ev"}' 'keys_unsorted[0]' 'evidence'
129
+ assert_json_field "each evidence entry carries its index for the checks (#1314)" \
130
+ '{"workItemId":"wi-ev"}' '.evidence[1].index' '1'
129
131
  assert_json_field "evidence block is surfaced from output.evidence" \
130
132
  '{"workItemId":"wi-ev"}' '[.evidence[].type] | join(",")' 'artifact,command'
131
133
  assert_json_field "no evidence warning when evidence is present" \
@@ -1779,12 +1779,20 @@ export declare const COMPLETION_EVIDENCE_CONSTANTS: {
1779
1779
  /** The two rollout modes for a completion that carries no evidence. */
1780
1780
  readonly MODES: readonly string[];
1781
1781
  /**
1782
- * Default mode for a completion with no evidence. `warn` (this release):
1783
- * accepted, logged, and the response carries a `warning`. `enforce` (next
1784
- * release): 400. Malformed evidence, missing artifacts, failing commands and
1785
- * `blocked` entries are handled the same in both modes.
1782
+ * Default mode for a completion with no evidence. `enforce` (default since
1783
+ * #1312): 400 `evidence_required`. `warn` (the escape hatch, set with
1784
+ * {@link ENV_MODE}): accepted, logged, and the response carries a `warning`.
1785
+ * Malformed evidence, missing artifacts, failing commands and `blocked`
1786
+ * entries are handled the same in both modes.
1786
1787
  */
1787
1788
  readonly EVIDENCE_ENFORCEMENT_MODE: "warn" | "enforce";
1789
+ /**
1790
+ * WorkItem types whose completion must carry evidence: a worker's
1791
+ * deliverable. Every other type is harness bookkeeping (triage, replans,
1792
+ * retros, reconciles, notifications) and may complete without it. An item
1793
+ * with no known type is treated as a deliverable.
1794
+ */
1795
+ readonly REQUIRED_FOR_TYPES: readonly string[];
1788
1796
  /** Env var that overrides {@link EVIDENCE_ENFORCEMENT_MODE} (`warn` | `enforce`). */
1789
1797
  readonly ENV_MODE: "CREWLY_EVIDENCE_MODE";
1790
1798
  /** Most evidence entries accepted on one completion. */
@@ -1800,8 +1808,25 @@ export declare const COMPLETION_EVIDENCE_CONSTANTS: {
1800
1808
  readonly MISSING: "evidence_required";
1801
1809
  readonly ARTIFACT_NOT_FOUND: "evidence_artifact_not_found";
1802
1810
  readonly ARTIFACT_UNRESOLVABLE: "evidence_artifact_relative_path";
1811
+ readonly ARTIFACT_EMPTY: "evidence_artifact_empty";
1812
+ readonly ARTIFACT_STALE: "evidence_artifact_stale";
1803
1813
  readonly COMMAND_FAILED: "evidence_command_failed";
1804
- };
1814
+ readonly REVIEW_UNCHECKED: "review_unchecked";
1815
+ readonly REVIEW_CHECKS_MALFORMED: "review_checks_malformed";
1816
+ readonly REVIEW_CHECK_FAILED: "review_check_failed";
1817
+ };
1818
+ /** Worker evidence entries listed, numbered, in a review item's description (#1314). */
1819
+ readonly REVIEW_LISTED_ENTRIES: 10;
1820
+ /** Outcomes a reviewer records for one check (#1314). */
1821
+ readonly CHECK_OUTCOMES: readonly string[];
1822
+ /** The shape of a reviewer's check record, quoted in every refusal (#1314). */
1823
+ readonly CHECKS_HINT: string;
1824
+ /**
1825
+ * A local file artifact last modified more than this before its WorkItem
1826
+ * was created is stale: it was not made for this task (#1313). The slack
1827
+ * covers clock skew and a file saved just before the item was filed.
1828
+ */
1829
+ readonly STALE_GRACE_MS: number;
1805
1830
  /** The shape a worker must send, quoted in every rejection and warning. */
1806
1831
  readonly SHAPE_HINT: string;
1807
1832
  };