@byollm/conformance 0.1.0-alpha.8 → 0.1.0-alpha.80

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.
@@ -29,7 +29,6 @@ import {
29
29
  signRequest
30
30
  } from "@byollm/protocol";
31
31
  import {
32
- Allowlist,
33
32
  Budgets,
34
33
  IngressLog,
35
34
  SpendLedger,
@@ -76,7 +75,6 @@ var EchoBackend = class {
76
75
  ok: false,
77
76
  code: "canceled",
78
77
  message: "the job was canceled",
79
- retryable: false,
80
78
  durationMs: Date.now() - started
81
79
  };
82
80
  }
@@ -94,9 +92,11 @@ function daemonConfig(options) {
94
92
  const baseUrl = metered ? metered.baseUrl : options.subscription ? void 0 : "http://127.0.0.1:11434/v1";
95
93
  return resolveConfig(
96
94
  DaemonConfig.parse({
97
- backends: {
95
+ services: {
98
96
  primary: {
99
- backend: backendId,
97
+ model: "echo-model",
98
+ kinds: ["llm.generate", "llm.chat"],
99
+ type: backendId,
100
100
  ...baseUrl === void 0 ? {} : { baseUrl },
101
101
  offer: options.offer,
102
102
  ...metered === void 0 ? {} : {
@@ -107,10 +107,6 @@ function daemonConfig(options) {
107
107
  }
108
108
  }
109
109
  },
110
- routes: {
111
- "llm.generate": { backend: "primary", model: "echo-model" },
112
- "llm.chat": { backend: "primary", model: "echo-model" }
113
- },
114
110
  concurrency: 4
115
111
  })
116
112
  );
@@ -118,12 +114,10 @@ function daemonConfig(options) {
118
114
  async function pairDaemon(target, options) {
119
115
  const home = await mkdtemp(join(tmpdir(), "byollm-conformance-"));
120
116
  const loaded = daemonConfig({
121
- offer: options.offer ?? "self",
117
+ offer: options.offer,
122
118
  subscription: options.subscription ?? false,
123
119
  ...options.metered === void 0 ? {} : { metered: options.metered }
124
120
  });
125
- const allowlist = new Allowlist(join(home, "allow.json"));
126
- await allowlist.load();
127
121
  const budgets = new Budgets(
128
122
  join(home, "budgets.json"),
129
123
  loaded.config.community
@@ -140,6 +134,7 @@ async function pairDaemon(target, options) {
140
134
  const fetchImpl = (input, init) => target.fetch(new Request(input, init));
141
135
  const capabilities = loaded.routes.map((route) => ({
142
136
  kind: route.kind,
137
+ service: route.service,
143
138
  backendId: route.backendId,
144
139
  backendClass: route.backendClass,
145
140
  model: route.model,
@@ -203,12 +198,13 @@ async function pairDaemon(target, options) {
203
198
  owner: result.pairing.owner,
204
199
  identity: {
205
200
  keys: () => deviceIdentity.load(Date.now()),
206
- // Pinned at pairing, exactly as a real daemon does.
207
- sitePinned: result.pairing.site
201
+ // Pinned at pairing, exactly as a real daemon does — the set the
202
+ // upstream answered with, keyed by each site's identity key id
203
+ // (cloud_009 §5). A direct site is one entry.
204
+ sites: new Map(Object.entries(result.pairing.sites))
208
205
  },
209
206
  daemonVersion: "conformance",
210
207
  loaded,
211
- allowlist,
212
208
  budgets,
213
209
  spend,
214
210
  ingress,
@@ -217,13 +213,11 @@ async function pairDaemon(target, options) {
217
213
  return {
218
214
  runner,
219
215
  backend,
220
- allowlist,
221
216
  runnerId: result.pairing.runnerId,
222
217
  owner: result.pairing.owner,
223
- token: result.pairing.token,
224
218
  keys: await deviceIdentity.load(Date.now()),
225
219
  identityKeys: () => deviceIdentity.load(Date.now()),
226
- sitePinned: result.pairing.site,
220
+ sitePinned: Object.values(result.pairing.sites)[0],
227
221
  home,
228
222
  ingress,
229
223
  spend,
@@ -309,6 +303,37 @@ async function claimOne(target, daemon) {
309
303
  if (!job) throw new Error("claim returned no jobs");
310
304
  return job;
311
305
  }
306
+ async function claimRaw(target, daemon, capabilityOverride) {
307
+ const capabilities = capabilityOverride ?? await daemon.runner.detectCapabilities();
308
+ const body = JSON.stringify({
309
+ protocolVersion: PROTOCOL_VERSION,
310
+ runnerId: daemon.runnerId,
311
+ capabilities,
312
+ max: 10
313
+ });
314
+ const signature = signRequest(daemon.keys, {
315
+ endpoint: "claim",
316
+ runnerId: daemon.runnerId,
317
+ issuedAt: Date.now(),
318
+ body
319
+ });
320
+ const response = await target.fetch(
321
+ new Request(`${target.origin}/byollm/claim`, {
322
+ method: "POST",
323
+ headers: {
324
+ "content-type": "application/json",
325
+ "x-byollm-runner": signature.runnerId,
326
+ "x-byollm-issued-at": String(signature.issuedAt),
327
+ "x-byollm-signature": signature.signature
328
+ },
329
+ body
330
+ })
331
+ );
332
+ if (response.status !== 200) {
333
+ throw new Error(`claim answered ${String(response.status)}`);
334
+ }
335
+ return (await response.json()).jobs;
336
+ }
312
337
  async function releaseLease(target, daemon, jobId, leaseId) {
313
338
  const body = JSON.stringify({
314
339
  protocolVersion: PROTOCOL_VERSION,
@@ -383,7 +408,11 @@ async function postResult(target, daemon, input) {
383
408
  const keys = await daemon.identityKeys();
384
409
  const sealer = input.sealWith ?? keys;
385
410
  const envelope = await seal({
386
- plaintext: JSON.stringify(input.outcome),
411
+ // `{ outcome, ran }` — cloud_008 §2.5.
412
+ plaintext: JSON.stringify({
413
+ outcome: input.outcome,
414
+ ran: { model: "test-model", backendClass: "http", durationMs: 1 }
415
+ }),
387
416
  senderKeys: sealer,
388
417
  recipientEncryptionPublic: daemon.sitePinned.encryption,
389
418
  context: {
@@ -401,11 +430,9 @@ async function postResult(target, daemon, input) {
401
430
  protocolVersion: PROTOCOL_VERSION,
402
431
  runnerId: daemon.runnerId,
403
432
  jobId: input.jobId,
433
+ leaseId: input.leaseId,
404
434
  envelope,
405
- disposition: input.disposition ?? input.outcome.outcome,
406
- model: "conformance-model",
407
- backendClass: "http",
408
- durationMs: 1
435
+ disposition: input.disposition ?? input.outcome.outcome
409
436
  });
410
437
  const signature = signRequest(daemon.keys, {
411
438
  endpoint: "result",
@@ -445,7 +472,7 @@ async function fetchGenuine(target, daemon, owner = "alice") {
445
472
  // The target's own name for the user, not the id it mapped that to —
446
473
  // passing a mapped id back in addresses a user the target never made.
447
474
  owner,
448
- audience: "self"
475
+ audience: "private"
449
476
  });
450
477
  for (let attempt = 0; attempt < 20; attempt += 1) {
451
478
  try {
@@ -475,13 +502,19 @@ var CHECKS = [
475
502
  title: "a runner token is bound to exactly the approving user",
476
503
  musts: ["PAIR_ONE_USER", "PAIR_INTERACTIVE"],
477
504
  async run(target) {
478
- const alice = await pairDaemon(target, { owner: "alice" });
505
+ const alice = await pairDaemon(target, {
506
+ owner: "alice",
507
+ offer: "private"
508
+ });
479
509
  try {
480
510
  assert(
481
511
  alice.owner === await ownerIdFor(target, "alice"),
482
512
  `runner was bound to "${alice.owner}", not to the approving user`
483
513
  );
484
- const bob = await pairDaemon(target, { owner: "bob" });
514
+ const bob = await pairDaemon(target, {
515
+ owner: "bob",
516
+ offer: "private"
517
+ });
485
518
  assert(
486
519
  bob.owner !== alice.owner,
487
520
  "two different approvers produced the same runner owner"
@@ -491,7 +524,7 @@ var CHECKS = [
491
524
  kind: "llm.generate",
492
525
  payload: prompt("alice's private prompt"),
493
526
  owner: "alice",
494
- audience: "self"
527
+ audience: "private"
495
528
  });
496
529
  await bob.runner.tick();
497
530
  await sleep(50);
@@ -513,7 +546,10 @@ var CHECKS = [
513
546
  title: "an enqueued job runs on the owner's daemon and the result comes back",
514
547
  musts: ["CLAIM_REQUIRES_CAPABILITY", "RESULT_IDEMPOTENT"],
515
548
  async run(target) {
516
- const daemon = await pairDaemon(target, { owner: "alice" });
549
+ const daemon = await pairDaemon(target, {
550
+ owner: "alice",
551
+ offer: "private"
552
+ });
517
553
  try {
518
554
  const job = await target.enqueue({
519
555
  kind: "llm.generate",
@@ -543,7 +579,10 @@ var CHECKS = [
543
579
  title: "a daemon is never handed a kind it did not advertise",
544
580
  musts: ["KIND_TYPED_ONLY", "CLAIM_REQUIRES_CAPABILITY"],
545
581
  async run(target) {
546
- const daemon = await pairDaemon(target, { owner: "alice" });
582
+ const daemon = await pairDaemon(target, {
583
+ owner: "alice",
584
+ offer: "private"
585
+ });
547
586
  try {
548
587
  const job = await target.enqueue({
549
588
  kind: "llm.chat",
@@ -562,6 +601,25 @@ var CHECKS = [
562
601
  daemon.backend.seen.length > before,
563
602
  "the advertised kind never reached the backend"
564
603
  );
604
+ const chat = await target.enqueue({
605
+ kind: "llm.chat",
606
+ payload: { messages: [{ role: "user", content: "not for you" }] },
607
+ owner: "alice"
608
+ });
609
+ const generateOnly = await claimRaw(target, daemon, [
610
+ {
611
+ kind: "llm.generate",
612
+ service: "local",
613
+ backendId: "openai-http",
614
+ backendClass: "http",
615
+ model: "echo-model",
616
+ offerScope: "private"
617
+ }
618
+ ]);
619
+ assert(
620
+ !generateOnly.some((offered) => offered.id === chat.id),
621
+ "a server offered `llm.chat` to a claim advertising only `llm.generate`"
622
+ );
565
623
  } finally {
566
624
  await daemon.dispose();
567
625
  }
@@ -572,14 +630,18 @@ var CHECKS = [
572
630
  title: "a job whose runner vanished is offered again, losing nothing",
573
631
  musts: ["LEASE_RECLAIMABLE", "LEASE_HONORED"],
574
632
  async run(target) {
575
- const dead = await pairDaemon(target, { owner: "alice", label: "dead" });
633
+ const dead = await pairDaemon(target, {
634
+ owner: "alice",
635
+ label: "dead",
636
+ offer: "private"
637
+ });
576
638
  const job = await target.enqueue({
577
639
  kind: "llm.generate",
578
640
  payload: prompt("work"),
579
641
  owner: "alice"
580
642
  });
581
643
  dead.backend.hangMs = 6e4;
582
- await dead.runner.tick();
644
+ const firstLease = await claimOne(target, dead);
583
645
  await waitFor(
584
646
  async () => {
585
647
  const state = await target.job(job.id);
@@ -591,35 +653,61 @@ var CHECKS = [
591
653
  await advance(target, target.leaseMs + 500);
592
654
  const alive = await pairDaemon(target, {
593
655
  owner: "alice",
594
- label: "alive"
656
+ label: "alive",
657
+ offer: "private"
595
658
  });
596
659
  try {
597
- await alive.runner.tick();
598
- await waitFor(async () => (await target.job(job.id))?.state === "ok", {
599
- what: "the reclaimed job to complete"
660
+ const reclaimed = await claimOne(target, alive);
661
+ assert(
662
+ reclaimed.id === job.id,
663
+ "the reclaiming daemon did not get the job"
664
+ );
665
+ const late = await postResult(target, dead, {
666
+ jobId: job.id,
667
+ leaseId: firstLease.lease.id,
668
+ outcome: { outcome: "ok", text: "from the machine that vanished" }
600
669
  });
670
+ const lateBody = await late.json().catch(() => ({}));
671
+ assert(
672
+ lateBody.accepted !== true,
673
+ "a site accepted a result from a runner whose lease had lapsed"
674
+ );
675
+ const midflight = await target.job(job.id);
676
+ assert(
677
+ !midflight?.outcome,
678
+ "a lapsed holder's result was recorded over a live grant"
679
+ );
680
+ const proper = await postResult(target, alive, {
681
+ jobId: job.id,
682
+ leaseId: reclaimed.lease.id,
683
+ outcome: { outcome: "ok", text: "from the machine that took over" }
684
+ });
685
+ assert(
686
+ proper.status === 200,
687
+ `the reclaiming daemon could not finish the job (${String(proper.status)})`
688
+ );
689
+ const final = await target.job(job.id);
690
+ assert(
691
+ final?.outcome?.text === "from the machine that took over",
692
+ "the reclaimed job did not record the current holder's result"
693
+ );
601
694
  } finally {
602
695
  await alive.dispose();
696
+ await dead.dispose();
603
697
  }
604
698
  }
605
699
  },
606
700
  {
607
701
  id: "C005_AUDIENCE_MATRIX",
608
- title: "all nine audience \xD7 offer-scope combinations behave as specified",
702
+ title: "all four audience x offer-scope combinations behave as specified",
609
703
  musts: ["AUDIENCE_BOTH_SIDES", "NAMED_LOCAL_ALLOWLIST"],
610
704
  async run(target) {
611
705
  const expected = {
612
- "self:self": false,
613
- "self:named": false,
614
- "self:public": false,
615
- "named:self": false,
616
- "named:named": false,
617
- // refused locally — allowlist is empty
618
- "named:public": true,
619
- "public:self": false,
620
- "public:named": false,
621
- // refused locally — allowlist is empty
622
- "public:public": true
706
+ "private:private": false,
707
+ "private:team": false,
708
+ "team:private": false,
709
+ "team:team": false
710
+ // refused locally — nothing admits alice
623
711
  };
624
712
  for (const audience of AUDIENCES) {
625
713
  for (const offer of OFFER_SCOPES) {
@@ -650,16 +738,30 @@ var CHECKS = [
650
738
  },
651
739
  {
652
740
  id: "C006_NAMED_LOCAL_ALLOWLIST",
653
- title: "a named job runs only once the daemon's own allowlist admits it",
741
+ /**
742
+ * Renamed with the release that made the sentence true — Amendment G, B2.
743
+ *
744
+ * The old title read "a named job runs only once the daemon's own
745
+ * allowlist admits it", which was true only under a generous reading of
746
+ * "own": the list was per-person and local, and a team member had to be
747
+ * enrolled on every machine by hand.
748
+ *
749
+ * The id does not change, per the id-stability law. What changes is the
750
+ * sentence, and it now names all three of the things a reader would
751
+ * otherwise take on faith — that the list is local, that its authority was
752
+ * established out of band, and that admission is a property of the asker
753
+ * rather than of the request.
754
+ */
755
+ title: "a team job is refused by a device whose upstream cannot say who the asker is, and is not offered to it again",
654
756
  musts: ["NAMED_LOCAL_ALLOWLIST", "REFUSAL_NOT_REOFFERED"],
655
757
  async run(target) {
656
- const bob = await pairDaemon(target, { owner: "bob", offer: "named" });
758
+ const bob = await pairDaemon(target, { owner: "bob", offer: "team" });
657
759
  try {
658
760
  const refused = await target.enqueue({
659
761
  kind: "llm.generate",
660
762
  payload: prompt("before"),
661
763
  owner: "alice",
662
- audience: "named"
764
+ audience: "team"
663
765
  });
664
766
  await bob.runner.tick();
665
767
  await sleep(80);
@@ -667,27 +769,10 @@ var CHECKS = [
667
769
  (await target.job(refused.id))?.state !== "ok",
668
770
  "a named job ran without the daemon's local allowlist admitting it"
669
771
  );
670
- const before = bob.backend.seen.length;
671
- await bob.runner.tick();
672
- await sleep(50);
772
+ const reoffered = await claimRaw(target, bob);
673
773
  assert(
674
- bob.backend.seen.length === before,
675
- "a refused job was re-offered to the runner that refused it"
676
- );
677
- await bob.allowlist.add(
678
- { origin: target.origin, owner: await ownerIdFor(target, "alice") },
679
- Date.now()
680
- );
681
- const allowed = await target.enqueue({
682
- kind: "llm.generate",
683
- payload: prompt("after"),
684
- owner: "alice",
685
- audience: "named"
686
- });
687
- await bob.runner.tick();
688
- await waitFor(
689
- async () => (await target.job(allowed.id))?.state === "ok",
690
- { what: "the allowed named job to run" }
774
+ !reoffered.some((job) => job.id === refused.id),
775
+ "a server re-offered a job to the runner that refused it"
691
776
  );
692
777
  } finally {
693
778
  await bob.dispose();
@@ -701,19 +786,15 @@ var CHECKS = [
701
786
  async run(target) {
702
787
  const bob = await pairDaemon(target, {
703
788
  owner: "bob",
704
- offer: "public",
789
+ offer: "team",
705
790
  subscription: true
706
791
  });
707
792
  try {
708
- await bob.allowlist.add(
709
- { origin: target.origin, owner: await ownerIdFor(target, "alice") },
710
- Date.now()
711
- );
712
793
  const job = await target.enqueue({
713
794
  kind: "llm.generate",
714
795
  payload: prompt("someone else's work"),
715
796
  owner: "alice",
716
- audience: "public"
797
+ audience: "team"
717
798
  });
718
799
  await bob.runner.tick();
719
800
  await sleep(80);
@@ -730,7 +811,7 @@ var CHECKS = [
730
811
  kind: "llm.generate",
731
812
  payload: prompt("my own work"),
732
813
  owner: "bob",
733
- audience: "self"
814
+ audience: "private"
734
815
  });
735
816
  await bob.runner.tick();
736
817
  await waitFor(async () => (await target.job(own.id))?.state === "ok", {
@@ -744,9 +825,17 @@ var CHECKS = [
744
825
  {
745
826
  id: "C008_REVOCATION",
746
827
  title: "a revoked daemon stops mid-queue",
747
- musts: ["REVOCATION_HONORED"],
828
+ // Both halves, and this check already proved both: the daemon learns it
829
+ // is revoked (`REVOCATION_HONORED`), *and* the upstream leaves the job
830
+ // queued rather than granting it (`REVOCATION_IMMEDIATE`). The second
831
+ // assertion was here and cited nothing — which is how a MUST comes to be
832
+ // declared in a spec, absent from the registry, and tested all along.
833
+ musts: ["REVOCATION_HONORED", "REVOCATION_IMMEDIATE"],
748
834
  async run(target) {
749
- const daemon = await pairDaemon(target, { owner: "alice" });
835
+ const daemon = await pairDaemon(target, {
836
+ owner: "alice",
837
+ offer: "private"
838
+ });
750
839
  try {
751
840
  await target.revokeRunner(daemon.runnerId);
752
841
  const job = await target.enqueue({
@@ -774,7 +863,10 @@ var CHECKS = [
774
863
  title: "cancel aborts a running job's backend call",
775
864
  musts: ["CANCEL_HONORED"],
776
865
  async run(target) {
777
- const daemon = await pairDaemon(target, { owner: "alice" });
866
+ const daemon = await pairDaemon(target, {
867
+ owner: "alice",
868
+ offer: "private"
869
+ });
778
870
  try {
779
871
  daemon.backend.hangMs = 3e4;
780
872
  const job = await target.enqueue({
@@ -802,39 +894,73 @@ var CHECKS = [
802
894
  title: "the first terminal outcome wins",
803
895
  musts: ["RESULT_IDEMPOTENT"],
804
896
  async run(target) {
805
- const daemon = await pairDaemon(target, { owner: "alice" });
897
+ const daemon = await pairDaemon(target, {
898
+ owner: "alice",
899
+ offer: "private"
900
+ });
806
901
  try {
807
902
  const job = await target.enqueue({
808
903
  kind: "llm.generate",
809
904
  payload: prompt("once"),
810
905
  owner: "alice"
811
906
  });
812
- await daemon.runner.tick();
813
- await waitFor(async () => (await target.job(job.id))?.state === "ok", {
814
- what: "the job to complete"
907
+ const claimed = await claimOne(target, daemon);
908
+ assert(claimed.id === job.id, "the harness could not claim its job");
909
+ const first = await postResult(target, daemon, {
910
+ jobId: job.id,
911
+ leaseId: claimed.lease.id,
912
+ outcome: { outcome: "ok", text: "the answer that counts" }
815
913
  });
816
- const first = await target.job(job.id);
817
- const response = await target.fetch(
818
- new Request(`${target.origin}/byollm/result`, {
819
- method: "POST",
820
- headers: { "content-type": "application/json" },
821
- body: JSON.stringify({
822
- protocolVersion: "0",
823
- runnerId: daemon.runnerId,
824
- jobId: job.id,
825
- outcome: { outcome: "ok", text: "SECOND ANSWER" },
826
- model: "echo-model",
827
- backendClass: "http",
828
- durationMs: 1
829
- })
830
- })
914
+ assert(
915
+ first.status === 200,
916
+ `a site refused the first result (${String(first.status)})`
917
+ );
918
+ const replay = await postResult(target, daemon, {
919
+ jobId: job.id,
920
+ leaseId: claimed.lease.id,
921
+ outcome: { outcome: "ok", text: "SECOND ANSWER" }
922
+ });
923
+ assert(
924
+ replay.status === 200,
925
+ `a replayed result was rejected rather than ignored (${String(replay.status)})`
926
+ );
927
+ const body = await replay.json();
928
+ assert(
929
+ body.accepted === false,
930
+ "a site reported a replayed result as newly accepted"
931
+ );
932
+ assert(
933
+ body.duplicate === true,
934
+ "a replay from the device that finished the job was not called a duplicate"
831
935
  );
832
- void response;
833
936
  const after = await target.job(job.id);
834
937
  assert(
835
- after?.outcome?.text === first?.outcome?.text,
836
- "a second result overwrote the first"
938
+ after?.outcome?.text === "the answer that counts",
939
+ `a second result overwrote the first (${String(after?.outcome?.text)})`
837
940
  );
941
+ const stranger = await pairDaemon(target, {
942
+ owner: "alice",
943
+ offer: "private"
944
+ });
945
+ try {
946
+ const foreign = await postResult(target, stranger, {
947
+ jobId: job.id,
948
+ leaseId: claimed.lease.id,
949
+ outcome: { outcome: "ok", text: "not this device's to answer" }
950
+ });
951
+ const foreignBody = await foreign.json().catch(() => ({}));
952
+ assert(
953
+ foreignBody["duplicate"] !== true,
954
+ "a site told a device that never held this job it was a duplicate"
955
+ );
956
+ const stillFirst = await target.job(job.id);
957
+ assert(
958
+ stillFirst?.outcome?.text === "the answer that counts",
959
+ "a stranger's result overwrote a terminal job"
960
+ );
961
+ } finally {
962
+ await stranger.dispose();
963
+ }
838
964
  } finally {
839
965
  await daemon.dispose();
840
966
  }
@@ -845,20 +971,23 @@ var CHECKS = [
845
971
  title: "a dependent job waits for its dependency, across two daemons",
846
972
  musts: ["DEPENDS_ON_GATING", "TTL_EXPIRY"],
847
973
  async run(target) {
848
- const alice = await pairDaemon(target, { owner: "alice" });
849
- const bob = await pairDaemon(target, { owner: "bob" });
974
+ const alice = await pairDaemon(target, {
975
+ owner: "alice",
976
+ offer: "private"
977
+ });
978
+ const bob = await pairDaemon(target, { owner: "bob", offer: "private" });
850
979
  try {
851
980
  const first = await target.enqueue({
852
981
  kind: "llm.generate",
853
982
  payload: prompt("step one"),
854
983
  owner: "bob",
855
- audience: "self"
984
+ audience: "private"
856
985
  });
857
986
  const second = await target.enqueue({
858
987
  kind: "llm.generate",
859
988
  payload: prompt("step two"),
860
989
  owner: "alice",
861
- audience: "self",
990
+ audience: "private",
862
991
  dependsOn: [first.id]
863
992
  });
864
993
  await alice.runner.tick();
@@ -919,7 +1048,10 @@ var CHECKS = [
919
1048
  title: "a dependent job's TTL starts when it becomes claimable, not at enqueue",
920
1049
  musts: ["TTL_EXPIRY"],
921
1050
  async run(target) {
922
- const daemon = await pairDaemon(target, { owner: "alice" });
1051
+ const daemon = await pairDaemon(target, {
1052
+ owner: "alice",
1053
+ offer: "private"
1054
+ });
923
1055
  try {
924
1056
  daemon.backend.hangMs = target.ttlMs * 2;
925
1057
  const first = await target.enqueue({
@@ -949,35 +1081,19 @@ var CHECKS = [
949
1081
  {
950
1082
  id: "C014_RESULT_PROVENANCE",
951
1083
  title: "a community result arrives marked untrusted, a self result does not",
952
- musts: ["RESULT_PROVENANCE"],
1084
+ // `PROVENANCE_NAMES_DEVICE` supersedes `RESULT_PROVENANCE` — a
1085
+ // strengthening rather than a rename. C030 is the other half: a label
1086
+ // means nothing unless a result whose signature does not verify against
1087
+ // the granted device is refused rather than recorded.
1088
+ musts: ["PROVENANCE_NAMES_DEVICE"],
953
1089
  async run(target) {
954
- const bob = await pairDaemon(target, { owner: "bob", offer: "public" });
1090
+ const bob = await pairDaemon(target, { owner: "bob", offer: "team" });
955
1091
  try {
956
- const community = await target.enqueue({
957
- kind: "llm.generate",
958
- payload: prompt("run this anywhere"),
959
- owner: "alice",
960
- audience: "public"
961
- });
962
- await bob.runner.tick();
963
- await waitFor(
964
- async () => (await target.job(community.id))?.state === "ok",
965
- { what: "the community job to complete" }
966
- );
967
- const delivered = await target.job(community.id);
968
- assert(
969
- delivered?.provenance?.untrusted === true,
970
- "a public result was not marked untrusted"
971
- );
972
- assert(
973
- delivered.provenance.runnerOwner === "bob",
974
- "the result did not carry the runner's owner"
975
- );
976
1092
  const own = await target.enqueue({
977
1093
  kind: "llm.generate",
978
1094
  payload: prompt("my own"),
979
1095
  owner: "bob",
980
- audience: "self"
1096
+ audience: "private"
981
1097
  });
982
1098
  await bob.runner.tick();
983
1099
  await waitFor(async () => (await target.job(own.id))?.state === "ok", {
@@ -997,7 +1113,10 @@ var CHECKS = [
997
1113
  title: "every executed prompt is in the ingress log before it runs",
998
1114
  musts: ["INGRESS_LOGGED_BEFORE_EXECUTION"],
999
1115
  async run(target) {
1000
- const daemon = await pairDaemon(target, { owner: "alice" });
1116
+ const daemon = await pairDaemon(target, {
1117
+ owner: "alice",
1118
+ offer: "private"
1119
+ });
1001
1120
  let ticking = Promise.resolve();
1002
1121
  try {
1003
1122
  daemon.backend.hangMs = 3e4;
@@ -1031,7 +1150,13 @@ var CHECKS = [
1031
1150
  {
1032
1151
  id: "C016_UNAUTHENTICATED_REFUSED",
1033
1152
  title: "the protocol endpoints refuse an unknown token",
1034
- musts: ["PAIR_ONE_USER"],
1153
+ // `CONSENT_BEFORE_ROUTE` on this plane. A relay has a consent record; a
1154
+ // direct site has pairing, and it is the same obligation — an upstream
1155
+ // routes to a device it has a record binding, and there is no discovery
1156
+ // path by which an unbound device receives work. Every endpoint is
1157
+ // checked rather than just `claim`, which is what makes it the absence
1158
+ // of a path rather than the absence of one door.
1159
+ musts: ["PAIR_ONE_USER", "CONSENT_BEFORE_ROUTE"],
1035
1160
  async run(target) {
1036
1161
  for (const endpoint of ["claim", "heartbeat", "result", "release"]) {
1037
1162
  const response = await target.fetch(
@@ -1041,7 +1166,7 @@ var CHECKS = [
1041
1166
  "content-type": "application/json",
1042
1167
  authorization: "Bearer definitely-not-a-real-token"
1043
1168
  },
1044
- body: JSON.stringify({ protocolVersion: "0" })
1169
+ body: JSON.stringify({ protocolVersion: PROTOCOL_VERSION2 })
1045
1170
  })
1046
1171
  );
1047
1172
  assert(
@@ -1054,11 +1179,19 @@ var CHECKS = [
1054
1179
  {
1055
1180
  id: "C017_METERED_DEFAULTS_SELF",
1056
1181
  title: "a paid backend is not shared until its owner says so, with a ceiling",
1057
- musts: ["METERED_DEFAULTS_SELF", "COST_NOT_CONFIGURABLE"],
1182
+ // `EFFECTIVE_OFFER_ONLY` too: bob asks for `public`, what reaches the
1183
+ // server is `self`, and the server acts on what it was told rather than
1184
+ // on what was wanted. That *is* the effective-offer rule, proved here
1185
+ // without being named.
1186
+ musts: [
1187
+ "METERED_DEFAULTS_SELF",
1188
+ "COST_NOT_CONFIGURABLE",
1189
+ "EFFECTIVE_OFFER_ONLY"
1190
+ ],
1058
1191
  async run(target) {
1059
1192
  const bob = await pairDaemon(target, {
1060
1193
  owner: "bob",
1061
- offer: "public",
1194
+ offer: "team",
1062
1195
  // Pointed at localhost — which changes nothing, because a named
1063
1196
  // provider's cost comes from the registry, not from an address
1064
1197
  // ({@link MUSTS.COST_NOT_CONFIGURABLE}).
@@ -1066,22 +1199,18 @@ var CHECKS = [
1066
1199
  });
1067
1200
  try {
1068
1201
  assert(
1069
- bob.loaded.routes.every((route) => route.offerScope === "self"),
1202
+ bob.loaded.routes.every((route) => route.offerScope === "private"),
1070
1203
  "a metered backend was advertised beyond its owner without consent"
1071
1204
  );
1072
1205
  assert(
1073
1206
  bob.loaded.routes.every((route) => route.cost === "metered"),
1074
1207
  "a metered provider was read as free because of its base URL"
1075
1208
  );
1076
- await bob.allowlist.add(
1077
- { origin: target.origin, owner: await ownerIdFor(target, "alice") },
1078
- Date.now()
1079
- );
1080
1209
  const job = await target.enqueue({
1081
1210
  kind: "llm.generate",
1082
1211
  payload: prompt("spend someone else's money"),
1083
1212
  owner: "alice",
1084
- audience: "public"
1213
+ audience: "team"
1085
1214
  });
1086
1215
  await bob.runner.tick();
1087
1216
  await sleep(80);
@@ -1097,7 +1226,7 @@ var CHECKS = [
1097
1226
  const availability = await target.runnerAvailability({
1098
1227
  kind: "llm.generate",
1099
1228
  owner: "alice",
1100
- audience: "public"
1229
+ audience: "team"
1101
1230
  });
1102
1231
  assert(
1103
1232
  !availability.available,
@@ -1107,7 +1236,7 @@ var CHECKS = [
1107
1236
  kind: "llm.generate",
1108
1237
  payload: prompt("my own work"),
1109
1238
  owner: "bob",
1110
- audience: "self"
1239
+ audience: "private"
1111
1240
  });
1112
1241
  await bob.runner.tick();
1113
1242
  await waitFor(async () => (await target.job(own.id))?.state === "ok", {
@@ -1125,7 +1254,7 @@ var CHECKS = [
1125
1254
  async run(target) {
1126
1255
  const bob = await pairDaemon(target, {
1127
1256
  owner: "bob",
1128
- offer: "public",
1257
+ offer: "team",
1129
1258
  metered: {
1130
1259
  // The generic backend pointed at a remote address. No registry entry
1131
1260
  // says what this costs; it is metered because of where it goes
@@ -1142,30 +1271,15 @@ var CHECKS = [
1142
1271
  "a remote backend was treated as free"
1143
1272
  );
1144
1273
  assert(
1145
- bob.loaded.routes.every((route) => route.offerScope === "public"),
1274
+ bob.loaded.routes.every((route) => route.offerScope === "team"),
1146
1275
  "a deliberately shared metered backend was narrowed anyway"
1147
1276
  );
1148
- await bob.allowlist.add(
1149
- { origin: target.origin, owner: await ownerIdFor(target, "alice") },
1150
- Date.now()
1151
- );
1152
- const first = await target.enqueue({
1153
- kind: "llm.generate",
1154
- payload: prompt("work bob agreed to pay for"),
1155
- owner: "alice",
1156
- audience: "public"
1157
- });
1158
- await bob.runner.tick();
1159
- await waitFor(
1160
- async () => (await target.job(first.id))?.state === "ok",
1161
- { what: "a consented metered job to run" }
1162
- );
1163
1277
  await bob.spend.record("primary", 900, Date.now());
1164
1278
  const second = await target.enqueue({
1165
1279
  kind: "llm.generate",
1166
1280
  payload: prompt("work past the ceiling"),
1167
1281
  owner: "alice",
1168
- audience: "public"
1282
+ audience: "team"
1169
1283
  });
1170
1284
  const seenBefore = bob.backend.seen.length;
1171
1285
  await bob.runner.tick();
@@ -1183,7 +1297,7 @@ var CHECKS = [
1183
1297
  kind: "llm.generate",
1184
1298
  payload: prompt("my own work, my own key"),
1185
1299
  owner: "bob",
1186
- audience: "self"
1300
+ audience: "private"
1187
1301
  });
1188
1302
  await bob.runner.tick();
1189
1303
  await waitFor(async () => (await target.job(own.id))?.state === "ok", {
@@ -1199,14 +1313,22 @@ var CHECKS = [
1199
1313
  title: "two runners racing one job \u2014 exactly one gets it",
1200
1314
  musts: ["CLAIM_ATOMIC"],
1201
1315
  async run(target) {
1202
- const a = await pairDaemon(target, { owner: "alice", label: "laptop" });
1203
- const b = await pairDaemon(target, { owner: "alice", label: "desktop" });
1316
+ const a = await pairDaemon(target, {
1317
+ owner: "alice",
1318
+ label: "laptop",
1319
+ offer: "private"
1320
+ });
1321
+ const b = await pairDaemon(target, {
1322
+ owner: "alice",
1323
+ label: "desktop",
1324
+ offer: "private"
1325
+ });
1204
1326
  try {
1205
1327
  const job = await target.enqueue({
1206
1328
  kind: "llm.generate",
1207
1329
  payload: prompt("only once, please"),
1208
1330
  owner: "alice",
1209
- audience: "self"
1331
+ audience: "private"
1210
1332
  });
1211
1333
  await Promise.all([a.runner.tick(), b.runner.tick()]);
1212
1334
  await waitFor(async () => (await target.job(job.id))?.state === "ok", {
@@ -1281,7 +1403,10 @@ var CHECKS = [
1281
1403
  title: "a runner advertises only what is installed and healthy",
1282
1404
  musts: ["CAPABILITY_IS_DETECTED"],
1283
1405
  async run(target) {
1284
- const daemon = await pairDaemon(target, { owner: "alice" });
1406
+ const daemon = await pairDaemon(target, {
1407
+ owner: "alice",
1408
+ offer: "private"
1409
+ });
1285
1410
  try {
1286
1411
  daemon.backend.healthy = false;
1287
1412
  const advertised = await daemon.runner.detectCapabilities();
@@ -1319,7 +1444,10 @@ var CHECKS = [
1319
1444
  // check does not establish.
1320
1445
  musts: ["KIND_NO_CODE"],
1321
1446
  async run(target) {
1322
- const daemon = await pairDaemon(target, { owner: "alice" });
1447
+ const daemon = await pairDaemon(target, {
1448
+ owner: "alice",
1449
+ offer: "private"
1450
+ });
1323
1451
  const SMUGGLED = ["command", "argv", "model", "baseUrl"];
1324
1452
  try {
1325
1453
  let refused = false;
@@ -1334,7 +1462,7 @@ var CHECKS = [
1334
1462
  baseUrl: "http://evil.test/v1"
1335
1463
  },
1336
1464
  owner: "alice",
1337
- audience: "self"
1465
+ audience: "private"
1338
1466
  });
1339
1467
  } catch {
1340
1468
  refused = true;
@@ -1364,7 +1492,7 @@ var CHECKS = [
1364
1492
  kind: "llm.generate",
1365
1493
  payload: prompt("ordinary text"),
1366
1494
  owner: "alice",
1367
- audience: "self"
1495
+ audience: "private"
1368
1496
  });
1369
1497
  await daemon.runner.tick();
1370
1498
  await waitFor(async () => (await target.job(ok.id))?.state === "ok", {
@@ -1471,7 +1599,7 @@ var CHECKS = [
1471
1599
  };
1472
1600
  const pending = await poll();
1473
1601
  assert(
1474
- pending["site"] === void 0,
1602
+ pending["sites"] === void 0,
1475
1603
  "a pending poll disclosed the site's keys before anyone approved"
1476
1604
  );
1477
1605
  await target.approvePairing(pairing.userCode, "alice");
@@ -1480,8 +1608,19 @@ var CHECKS = [
1480
1608
  approved["status"] === "approved",
1481
1609
  `poll after approval said "${String(approved["status"])}"`
1482
1610
  );
1483
- const site = PublicIdentity.safeParse(approved["site"]);
1484
- assert(site.success, "the approval carried no usable site identity");
1611
+ const offered = approved["sites"];
1612
+ assert(
1613
+ typeof offered === "object" && offered !== null,
1614
+ "the approval carried no sites to pin"
1615
+ );
1616
+ const parsed = Object.values(offered).map(
1617
+ (value) => PublicIdentity.safeParse(value)
1618
+ );
1619
+ assert(
1620
+ parsed.length > 0 && parsed.every((entry) => entry.success),
1621
+ "the approval carried no usable site identity"
1622
+ );
1623
+ const site = parsed[0];
1485
1624
  assert(
1486
1625
  verifyPublicIdentity(site.data),
1487
1626
  "the site's encryption key is not signed by the identity it presented"
@@ -1493,7 +1632,10 @@ var CHECKS = [
1493
1632
  title: "authentication is a signature over the request, not a secret",
1494
1633
  musts: ["REQUESTS_SIGNED_NOT_BEARER"],
1495
1634
  async run(target) {
1496
- const daemon = await pairDaemon(target, { owner: "alice" });
1635
+ const daemon = await pairDaemon(target, {
1636
+ owner: "alice",
1637
+ offer: "private"
1638
+ });
1497
1639
  try {
1498
1640
  const body = JSON.stringify({
1499
1641
  protocolVersion: PROTOCOL_VERSION2,
@@ -1565,13 +1707,16 @@ var CHECKS = [
1565
1707
  title: "a release acts on the lease it names, not whatever lease exists",
1566
1708
  musts: ["LEASE_SCOPED_BY_GRANT"],
1567
1709
  async run(target) {
1568
- const daemon = await pairDaemon(target, { owner: "alice" });
1710
+ const daemon = await pairDaemon(target, {
1711
+ owner: "alice",
1712
+ offer: "private"
1713
+ });
1569
1714
  try {
1570
1715
  const job = await target.enqueue({
1571
1716
  kind: "llm.generate",
1572
1717
  payload: prompt("run me once"),
1573
1718
  owner: "alice",
1574
- audience: "self"
1719
+ audience: "private"
1575
1720
  });
1576
1721
  const first = await claimOne(target, daemon);
1577
1722
  assert(
@@ -1605,13 +1750,16 @@ var CHECKS = [
1605
1750
  title: "a claim carries routing metadata and no work",
1606
1751
  musts: ["STUB_METADATA_EXHAUSTIVE"],
1607
1752
  async run(target) {
1608
- const daemon = await pairDaemon(target, { owner: "alice" });
1753
+ const daemon = await pairDaemon(target, {
1754
+ owner: "alice",
1755
+ offer: "private"
1756
+ });
1609
1757
  try {
1610
1758
  await target.enqueue({
1611
1759
  kind: "llm.generate",
1612
1760
  payload: prompt("this must not appear in a claim response"),
1613
1761
  owner: "alice",
1614
- audience: "self"
1762
+ audience: "private"
1615
1763
  });
1616
1764
  const stub = await claimOne(target, daemon);
1617
1765
  const asRecord = stub;
@@ -1670,13 +1818,16 @@ var CHECKS = [
1670
1818
  musts: ["ENVELOPE_SEALED_AND_SIGNED"],
1671
1819
  async run(target) {
1672
1820
  const secret = "a prompt nobody should read from storage";
1673
- const daemon = await pairDaemon(target, { owner: "alice" });
1821
+ const daemon = await pairDaemon(target, {
1822
+ owner: "alice",
1823
+ offer: "private"
1824
+ });
1674
1825
  try {
1675
1826
  const job = await target.enqueue({
1676
1827
  kind: "llm.generate",
1677
1828
  payload: prompt(secret),
1678
1829
  owner: "alice",
1679
- audience: "self"
1830
+ audience: "private"
1680
1831
  });
1681
1832
  const stored = await target.job(job.id);
1682
1833
  assert(
@@ -1709,7 +1860,10 @@ var CHECKS = [
1709
1860
  title: "a daemon refuses work not signed by the site it pinned",
1710
1861
  musts: ["ENVELOPE_SEALED_AND_SIGNED"],
1711
1862
  async run(target) {
1712
- const daemon = await pairDaemon(target, { owner: "alice" });
1863
+ const daemon = await pairDaemon(target, {
1864
+ owner: "alice",
1865
+ offer: "private"
1866
+ });
1713
1867
  try {
1714
1868
  const keys = await daemon.identityKeys();
1715
1869
  const relay = generateKeys(Date.now());
@@ -1754,9 +1908,16 @@ var CHECKS = [
1754
1908
  {
1755
1909
  id: "C030_SITE_REFUSES_UNSIGNED_RESULTS",
1756
1910
  title: "a site refuses a result not signed by the device that ran it",
1757
- musts: ["ENVELOPE_SEALED_AND_SIGNED"],
1911
+ // The proof-of-possession half of `PROVENANCE_NAMES_DEVICE`: attribution
1912
+ // by a signature that verifies against the device the lease was granted
1913
+ // to, rather than by a key id carried beside the result. Carrying an id
1914
+ // is not proving possession, and a forger writes whatever it likes.
1915
+ musts: ["ENVELOPE_SEALED_AND_SIGNED", "PROVENANCE_NAMES_DEVICE"],
1758
1916
  async run(target) {
1759
- const daemon = await pairDaemon(target, { owner: "alice" });
1917
+ const daemon = await pairDaemon(target, {
1918
+ owner: "alice",
1919
+ offer: "private"
1920
+ });
1760
1921
  try {
1761
1922
  const job = await target.enqueue({
1762
1923
  kind: "llm.generate",
@@ -1768,6 +1929,7 @@ var CHECKS = [
1768
1929
  const relay = generateKeys(Date.now());
1769
1930
  const forged = await postResult(target, daemon, {
1770
1931
  jobId: job.id,
1932
+ leaseId: claimed.lease.id,
1771
1933
  outcome: { outcome: "ok", text: "an answer the device never gave" },
1772
1934
  sealWith: relay
1773
1935
  });
@@ -1782,6 +1944,7 @@ var CHECKS = [
1782
1944
  );
1783
1945
  const real = await postResult(target, daemon, {
1784
1946
  jobId: job.id,
1947
+ leaseId: claimed.lease.id,
1785
1948
  outcome: { outcome: "ok", text: "the genuine answer" }
1786
1949
  });
1787
1950
  assert(
@@ -1790,6 +1953,7 @@ var CHECKS = [
1790
1953
  );
1791
1954
  const lying = await postResult(target, daemon, {
1792
1955
  jobId: job.id,
1956
+ leaseId: claimed.lease.id,
1793
1957
  outcome: {
1794
1958
  outcome: "error",
1795
1959
  code: "backend-error",
@@ -1806,11 +1970,101 @@ var CHECKS = [
1806
1970
  await daemon.dispose();
1807
1971
  }
1808
1972
  }
1973
+ },
1974
+ {
1975
+ id: "C032_SERVER_REFUSES_TO_OFFER",
1976
+ title: "a claim is not answered with work the claimer may not run",
1977
+ musts: ["AUDIENCE_BOTH_SIDES"],
1978
+ async run(target) {
1979
+ const bob = await pairDaemon(target, { owner: "bob", offer: "team" });
1980
+ try {
1981
+ const priv = await target.enqueue({
1982
+ kind: "llm.generate",
1983
+ payload: prompt("alice's own machines only"),
1984
+ owner: "alice",
1985
+ audience: "private"
1986
+ });
1987
+ const offered = await claimRaw(target, bob);
1988
+ assert(
1989
+ !offered.some((job) => job.id === priv.id),
1990
+ "a server offered a `self` job to a device its owner does not own"
1991
+ );
1992
+ const shared = await target.enqueue({
1993
+ kind: "llm.generate",
1994
+ payload: prompt("anyone may run this"),
1995
+ owner: "alice",
1996
+ audience: "team"
1997
+ });
1998
+ const second = await claimRaw(target, bob);
1999
+ assert(
2000
+ second.some((job) => job.id === shared.id),
2001
+ "a server withheld a `public` job from a public-offering device"
2002
+ );
2003
+ } finally {
2004
+ await bob.dispose();
2005
+ }
2006
+ }
2007
+ },
2008
+ {
2009
+ id: "C031_ROSTER_NOT_DISCLOSED",
2010
+ title: "a claimed stub carries no list of who may run the job",
2011
+ musts: ["ROSTER_NOT_DISCLOSED"],
2012
+ async run(target) {
2013
+ const daemon = await pairDaemon(target, {
2014
+ owner: "alice",
2015
+ offer: "private"
2016
+ });
2017
+ try {
2018
+ const job = await target.enqueue({
2019
+ kind: "llm.generate",
2020
+ payload: prompt("who else is on this roster"),
2021
+ owner: "alice",
2022
+ audience: "team",
2023
+ // The site restricts the job to people who are not this daemon's
2024
+ // owner. A stub that carried the list would be handing a routing
2025
+ // party the membership of alice's group.
2026
+ audienceAllow: ["alice", "carol", "erin"]
2027
+ });
2028
+ const claimed = await claimOne(target, daemon);
2029
+ assert(
2030
+ claimed.id === job.id,
2031
+ "the harness could not claim its own named job"
2032
+ );
2033
+ const asRecord = claimed;
2034
+ assert(
2035
+ asRecord["audienceAllow"] === void 0,
2036
+ "a claimed stub carried audienceAllow"
2037
+ );
2038
+ const parsed = ClaimedStub.safeParse(claimed);
2039
+ assert(
2040
+ parsed.success,
2041
+ "the claim response is not a valid stub, so its fields prove nothing"
2042
+ );
2043
+ const wire = JSON.stringify(claimed);
2044
+ for (const member of ["carol", "erin"]) {
2045
+ assert(
2046
+ !wire.includes(member),
2047
+ `a claimed stub disclosed roster member "${member}"`
2048
+ );
2049
+ }
2050
+ assert(
2051
+ claimed.audience === "team",
2052
+ "the stub lost the audience routing decides on"
2053
+ );
2054
+ assert(
2055
+ typeof claimed.owner === "string" && claimed.owner.length > 0,
2056
+ "the stub lost the owner"
2057
+ );
2058
+ } finally {
2059
+ await daemon.dispose();
2060
+ }
2061
+ }
1809
2062
  }
1810
2063
  ];
1811
2064
 
1812
2065
  // src/certify.ts
1813
2066
  import {
2067
+ kindsOf,
1814
2068
  MUSTS,
1815
2069
  MUST_IDS,
1816
2070
  mustsVerifiedBy
@@ -1854,7 +2108,7 @@ function uncoveredMusts(checks = CHECKS) {
1854
2108
  return mustsVerifiedBy("conformance").filter((id) => !covered.has(id));
1855
2109
  }
1856
2110
  function miscoveredMusts(checks = CHECKS) {
1857
- return [...new Set(checks.flatMap((check) => check.musts))].filter((id) => MUSTS[id].verifiedBy !== "conformance").sort();
2111
+ return [...new Set(checks.flatMap((check) => check.musts))].filter((id) => !kindsOf(MUSTS[id]).includes("conformance")).sort();
1858
2112
  }
1859
2113
  var VERIFICATION_NOTE = "(`adversarial` = proved by the reference daemon's own suites; `construction` = true by code shape; `operator` = a deployment claim, verifiable only by audit or source. None is asserted by this run.)";
1860
2114
  function formatReport(report) {
@@ -1882,13 +2136,13 @@ function formatReport(report) {
1882
2136
  }
1883
2137
  }
1884
2138
  const elsewhere = MUST_IDS.filter(
1885
- (id) => MUSTS[id].verifiedBy !== "conformance"
2139
+ (id) => !kindsOf(MUSTS[id]).includes("conformance")
1886
2140
  );
1887
2141
  if (elsewhere.length > 0) {
1888
2142
  lines.push("");
1889
2143
  lines.push(" Verified elsewhere, not by this kit:");
1890
2144
  for (const kind of ["adversarial", "construction", "operator"]) {
1891
- const ids = elsewhere.filter((id) => MUSTS[id].verifiedBy === kind);
2145
+ const ids = elsewhere.filter((id) => kindsOf(MUSTS[id]).includes(kind));
1892
2146
  if (ids.length === 0) continue;
1893
2147
  lines.push(` ${kind}: ${ids.join(", ")}`);
1894
2148
  }
@@ -1911,4 +2165,4 @@ export {
1911
2165
  miscoveredMusts,
1912
2166
  formatReport
1913
2167
  };
1914
- //# sourceMappingURL=chunk-EXNALQ5D.js.map
2168
+ //# sourceMappingURL=chunk-MSM6QP2N.js.map