@byollm/conformance 0.1.0-alpha.7 → 0.1.0-alpha.71

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