@brightbeamai/chap-coordinator 0.2.9 → 0.2.10

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.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as CoordinatorOptions, a as Coordinator } from './api-DE78DA0o.cjs';
2
- export { b as CoordinatorApi, c as CoordinatorError, d as CredentialVerifier, E as EscalationPolicyFn, H as Handler, I as IdFactory, P as PRIVILEGED_METHODS, R as ReviewDepthPolicyFn, e as RoutingPolicyFn, S as ScittReceiptVerifier, f as ScittSubmitter, T as TokenVerifier, g as call, m as makeApi } from './api-DE78DA0o.cjs';
1
+ import { C as CoordinatorOptions, a as Coordinator } from './api-CcT_8H5j.cjs';
2
+ export { b as CoordinatorApi, c as CoordinatorError, d as CredentialVerifier, E as EscalationPolicyFn, H as Handler, I as IdFactory, P as PRIVILEGED_METHODS, R as ReviewDepthPolicyFn, e as RoutingPolicyFn, S as ScittReceiptVerifier, f as ScittSubmitter, T as TokenVerifier, g as call, m as makeApi } from './api-CcT_8H5j.cjs';
3
3
  export { MethodName, MethodParams, MethodResult, MethodTable } from './methods.cjs';
4
4
  export { MemoryStore, Store, WorkspaceRecord } from './storage/store.cjs';
5
5
  export { ArtefactId, ArtefactRoutingHints, AuditEntry, AuditListener, Deliberation, DeliberationVote, Envelope, Handoff, HandoffTaskItem, JsonPatchOp, Jwk, KeyRecord, Member, Mode, OverrideArtefact, ParticipantType, ParticipantUri, PauseScope, ReviewDecision, RouteDecisionArtefact, SnapshotArtefact, Task, TaskId, TaskRoutingHints, TaskState, WhisperPrompt, Workspace, WorkspaceId, WorkspaceState, modeLE } from './types.cjs';
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as CoordinatorOptions, a as Coordinator } from './api-CPEk0V6i.js';
2
- export { b as CoordinatorApi, c as CoordinatorError, d as CredentialVerifier, E as EscalationPolicyFn, H as Handler, I as IdFactory, P as PRIVILEGED_METHODS, R as ReviewDepthPolicyFn, e as RoutingPolicyFn, S as ScittReceiptVerifier, f as ScittSubmitter, T as TokenVerifier, g as call, m as makeApi } from './api-CPEk0V6i.js';
1
+ import { C as CoordinatorOptions, a as Coordinator } from './api-Cvkhcalw.js';
2
+ export { b as CoordinatorApi, c as CoordinatorError, d as CredentialVerifier, E as EscalationPolicyFn, H as Handler, I as IdFactory, P as PRIVILEGED_METHODS, R as ReviewDepthPolicyFn, e as RoutingPolicyFn, S as ScittReceiptVerifier, f as ScittSubmitter, T as TokenVerifier, g as call, m as makeApi } from './api-Cvkhcalw.js';
3
3
  export { MethodName, MethodParams, MethodResult, MethodTable } from './methods.js';
4
4
  export { MemoryStore, Store, WorkspaceRecord } from './storage/store.js';
5
5
  export { ArtefactId, ArtefactRoutingHints, AuditEntry, AuditListener, Deliberation, DeliberationVote, Envelope, Handoff, HandoffTaskItem, JsonPatchOp, Jwk, KeyRecord, Member, Mode, OverrideArtefact, ParticipantType, ParticipantUri, PauseScope, ReviewDecision, RouteDecisionArtefact, SnapshotArtefact, Task, TaskId, TaskRoutingHints, TaskState, WhisperPrompt, Workspace, WorkspaceId, WorkspaceState, modeLE } from './types.js';
package/dist/index.js CHANGED
@@ -211,6 +211,7 @@ var E = {
211
211
  NOT_AUTHORISED: -32011,
212
212
  PATCH_FAILED: -32012,
213
213
  REVIEW_LAPSED: -32013,
214
+ REVIEW_ALREADY_OPEN: -32014,
214
215
  // whisper/1.0 profile (profiles/whisper.md S6)
215
216
  WHISPER_ALREADY_ANSWERED: -32020,
216
217
  WHISPER_LAPSED: -32021,
@@ -237,6 +238,7 @@ var E = {
237
238
  SIG_KEY_NOT_FOUND: -32071,
238
239
  SIG_KEY_REVOKED: -32072,
239
240
  SIG_ROTATION_KEY_MISMATCH: -32073,
241
+ SIG_ARTEFACT_DIGEST_MISMATCH: -32074,
240
242
  // audit-scitt/1.0 profile (profiles/audit-scitt.md S8)
241
243
  SCITT_UNREACHABLE: -32080,
242
244
  SCITT_STATEMENT_REJECTED: -32081,
@@ -704,6 +706,12 @@ function registerAuditScitt(coord) {
704
706
  if (!(ws.chain_enabled || coord.options.enableChain)) {
705
707
  return { error: rpcError(E.PARAMS, "Chain not enabled for this workspace") };
706
708
  }
709
+ if (p.from_seq !== void 0 || p.to_seq !== void 0) {
710
+ return { error: rpcError(
711
+ E.PARAMS,
712
+ "Range verification is not implemented; omit from_seq and to_seq to verify the whole log."
713
+ ) };
714
+ }
707
715
  let start = ws.audit.findIndex((e) => e.prev_hash != null);
708
716
  if (start < 0) start = ws.audit.length;
709
717
  const errors = [];
@@ -715,16 +723,35 @@ function registerAuditScitt(coord) {
715
723
  }
716
724
  prev = sha256Hex(Buffer.concat([canonicalize(e.envelope), Buffer.from(expectedPrev, "utf-8")]));
717
725
  }
718
- const storedHead = ws.chain_head ?? ZERO_HASH;
726
+ const storedHead = ws.chain_head === void 0 || ws.chain_head === null ? ZERO_HASH : ws.chain_head;
719
727
  if (prev !== storedHead) {
720
728
  errors.push("chain_head mismatch: replay does not match stored head");
721
729
  }
722
730
  if (errors.length) {
723
731
  return { error: rpcError(E.PARAMS, errors.join("; ")) };
724
732
  }
733
+ const entriesTotal = ws.audit.length;
734
+ const entriesChecked = entriesTotal - start;
735
+ const entriesUnchecked = start;
736
+ if (entriesUnchecked > 0) {
737
+ return { result: {
738
+ status: "not_evaluated",
739
+ ok: false,
740
+ reason: "unchained_prefix",
741
+ entries_total: entriesTotal,
742
+ entries_checked: entriesChecked,
743
+ entries_unchecked: entriesUnchecked,
744
+ checked_from_seq: entriesChecked > 0 ? ws.audit[start].seq : null,
745
+ chain_head: storedHead
746
+ } };
747
+ }
725
748
  return { result: {
749
+ status: "verified",
726
750
  ok: true,
727
- entries_checked: ws.audit.length - start,
751
+ entries_total: entriesTotal,
752
+ entries_checked: entriesChecked,
753
+ entries_unchecked: 0,
754
+ checked_from_seq: entriesChecked > 0 ? ws.audit[start].seq : null,
728
755
  chain_head: storedHead
729
756
  } };
730
757
  });
@@ -2415,12 +2442,38 @@ var Coordinator = class {
2415
2442
  const reviewers = Array.isArray(to) ? to : typeof to === "string" ? [to] : [];
2416
2443
  if (!reviewers.length) return { error: rpcError(E.PARAMS, "review.request needs 'to'") };
2417
2444
  const now = this.now();
2445
+ const rule = p.rule || "any_one_approves";
2446
+ if (task.state === "review_requested" && task.review) {
2447
+ if (contentHash(task.pending_artefact) !== contentHash(p.artefact)) {
2448
+ return { error: rpcError(
2449
+ E.REVIEW_ALREADY_OPEN,
2450
+ "A review is already open on this task with different content. Decide, abstain, escalate or cancel it before requesting review of a new artefact."
2451
+ ) };
2452
+ }
2453
+ if (rule !== task.review.rule) {
2454
+ return { error: rpcError(
2455
+ E.REVIEW_ALREADY_OPEN,
2456
+ `Cannot change the decision rule of an open review (currently ${task.review.rule})`
2457
+ ) };
2458
+ }
2459
+ for (const r of reviewers) {
2460
+ if (!task.review.requested_to.includes(r)) task.review.requested_to.push(r);
2461
+ }
2462
+ if (p.deadline !== void 0) task.review.deadline = p.deadline;
2463
+ task.updated_at = now;
2464
+ return { result: {
2465
+ state: "review_requested",
2466
+ review_id: task.id,
2467
+ amended: true,
2468
+ requested_to: [...task.review.requested_to]
2469
+ } };
2470
+ }
2418
2471
  task.state = "review_requested";
2419
2472
  task.updated_at = now;
2420
2473
  task.review = {
2421
2474
  requested_at: now,
2422
2475
  requested_to: reviewers,
2423
- rule: p.rule || "any_one_approves",
2476
+ rule,
2424
2477
  deadline: p.deadline,
2425
2478
  decisions: []
2426
2479
  };
@@ -2428,6 +2481,37 @@ var Coordinator = class {
2428
2481
  task.pending_artefact = p.artefact;
2429
2482
  return { result: { state: "review_requested", review_id: task.id } };
2430
2483
  }
2484
+ /**
2485
+ * Verify an optional `approved_artefact_digest` against the artefact under
2486
+ * review (review/1.0 S3.2).
2487
+ *
2488
+ * The digest sits in params, so it is inside whatever the envelope signature
2489
+ * covers: the decision then attests the content the reviewer saw rather than
2490
+ * a task reference, and a relying party can check it without trusting the
2491
+ * Coordinator that produced it. Absent, behaviour is exactly as before.
2492
+ *
2493
+ * On mismatch nothing is recorded and no state changes, so a client that
2494
+ * computes the wrong digest refuses only its own decision.
2495
+ */
2496
+ checkArtefactDigest(p, task) {
2497
+ const declared = p.approved_artefact_digest;
2498
+ if (declared === void 0 || declared === null) return null;
2499
+ if (typeof declared !== "string") {
2500
+ return { error: rpcError(E.PARAMS, "approved_artefact_digest must be a string") };
2501
+ }
2502
+ if (task.pending_artefact === void 0) {
2503
+ return { error: rpcError(E.PARAMS, "No artefact under review to bind a digest to") };
2504
+ }
2505
+ const actual = contentHash(task.pending_artefact);
2506
+ if (declared !== actual) {
2507
+ return { error: rpcError(
2508
+ E.SIG_ARTEFACT_DIGEST_MISMATCH,
2509
+ "approved_artefact_digest does not match the artefact under review",
2510
+ { declared, actual }
2511
+ ) };
2512
+ }
2513
+ return null;
2514
+ }
2431
2515
  opDecide(p, kind) {
2432
2516
  const miss = missing(p, ["workspace", "from", "task_id"]);
2433
2517
  if (miss) return { error: rpcError(E.PARAMS, `Missing field: ${miss}`) };
@@ -2444,6 +2528,8 @@ var Coordinator = class {
2444
2528
  }
2445
2529
  const notReviewer = this.requireReviewer(task, p.from);
2446
2530
  if (notReviewer) return notReviewer;
2531
+ const digestError = this.checkArtefactDigest(p, task);
2532
+ if (digestError) return digestError;
2447
2533
  const now = this.now();
2448
2534
  task.review.decisions.push({
2449
2535
  reviewer: p.from,
@@ -2478,6 +2564,8 @@ var Coordinator = class {
2478
2564
  }
2479
2565
  const notReviewer = this.requireReviewer(task, p.from);
2480
2566
  if (notReviewer) return notReviewer;
2567
+ const digestError = this.checkArtefactDigest(p, task);
2568
+ if (digestError) return digestError;
2481
2569
  const base = task.pending_artefact;
2482
2570
  if (base === void 0) return { error: rpcError(E.PARAMS, "No base artefact for override") };
2483
2571
  let applied;