@brightbeamai/chap-coordinator 0.2.12 → 0.2.13

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/dist/index.js CHANGED
@@ -1747,6 +1747,7 @@ function reply(env, body) {
1747
1747
  else out.result = body.result;
1748
1748
  return out;
1749
1749
  }
1750
+ var REVIEW_REQUEST_STOPPED = ["cancelled", "superseded", "paused"];
1750
1751
  var Coordinator = class {
1751
1752
  workspaces = /* @__PURE__ */ new Map();
1752
1753
  options;
@@ -2422,6 +2423,12 @@ var Coordinator = class {
2422
2423
  if (!legal[task.state]?.includes(newState)) {
2423
2424
  return { error: rpcError(E.PARAMS, `Illegal transition ${task.state} -> ${newState}`) };
2424
2425
  }
2426
+ if (newState === "completed" && task.review_required) {
2427
+ return { error: rpcError(
2428
+ E.PARAMS,
2429
+ "This task requires review. Submit the output with task.complete, which opens the review; a reviewer decision completes it."
2430
+ ) };
2431
+ }
2425
2432
  task.state = newState;
2426
2433
  task.updated_at = this.now();
2427
2434
  task.history.push({
@@ -2447,11 +2454,11 @@ var Coordinator = class {
2447
2454
  task.pending_artefact = p.output;
2448
2455
  if (!task.review) {
2449
2456
  const producer = p.from;
2450
- const eligible = [...ws.members.keys()].filter((uri) => uri !== producer && uri !== task.assignee);
2457
+ const eligible = [...ws.members.entries()].filter(([uri, member]) => uri !== producer && uri !== task.assignee && member.type === "human").map(([uri]) => uri);
2451
2458
  if (eligible.length === 0) {
2452
2459
  return { error: rpcError(
2453
2460
  E.NOT_AUTHORISED,
2454
- "Task requires review but has no eligible reviewer (needs a member other than its assignee and completer)"
2461
+ "Task requires review but has no eligible human reviewer (needs a human member other than its assignee and completer)"
2455
2462
  ) };
2456
2463
  }
2457
2464
  task.review = { requested_at: now, requested_to: eligible, rule: "any_one_approves", decisions: [] };
@@ -2512,11 +2519,15 @@ var Coordinator = class {
2512
2519
  if (notMember) return notMember;
2513
2520
  const task = ws.tasks.get(p.task_id);
2514
2521
  if (!task) return { error: rpcError(E.PARAMS, "Unknown task") };
2522
+ if (REVIEW_REQUEST_STOPPED.includes(task.state)) {
2523
+ return { error: rpcError(E.NOT_REVIEWABLE, `Cannot request review for task in state: ${task.state}`) };
2524
+ }
2515
2525
  const to = p.to;
2516
2526
  const reviewers = Array.isArray(to) ? to : typeof to === "string" ? [to] : [];
2517
2527
  if (!reviewers.length) return { error: rpcError(E.PARAMS, "review.request needs 'to'") };
2518
2528
  const now = this.now();
2519
- const rule = p.rule || "any_one_approves";
2529
+ const declaredRule = p.rule;
2530
+ const rule = declaredRule || "any_one_approves";
2520
2531
  if (!reviewRuleSupported(rule)) {
2521
2532
  return { error: rpcError(E.PARAMS, `Unsupported review rule ${JSON.stringify(rule)}: review/1.0 supports any_one_approves, all_approve, quorum:<n>`) };
2522
2533
  }
@@ -2527,7 +2538,7 @@ var Coordinator = class {
2527
2538
  "A review is already open on this task with different content. Decide, abstain, escalate or cancel it before requesting review of a new artefact."
2528
2539
  ) };
2529
2540
  }
2530
- if (rule !== task.review.rule) {
2541
+ if (declaredRule !== void 0 && declaredRule !== task.review.rule) {
2531
2542
  return { error: rpcError(
2532
2543
  E.REVIEW_ALREADY_OPEN,
2533
2544
  `Cannot change the decision rule of an open review (currently ${task.review.rule})`