@byollm/protocol 0.1.0-alpha.57 → 0.1.0-alpha.59

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.ts CHANGED
@@ -22,9 +22,9 @@ type BackendClass = z.infer<typeof BackendClass>;
22
22
  *
23
23
  * This replaced a two-valued `account` field that conflated two unrelated
24
24
  * constraints and, in doing so, left a hole: `openai-http` was "open", but it
25
- * accepts an API key, so an owner could point it at a paid endpoint, offer it
26
- * `public`, and donate their credit balance to strangers. The community
27
- * budgets cap job *count*, not spend.
25
+ * accepts an API key, so an owner could point it at a paid endpoint, share it,
26
+ * and donate their credit balance to strangers. The community budgets cap job
27
+ * *count*, not spend.
28
28
  *
29
29
  * - `free` — local compute. Costs electricity, not money. Shareable.
30
30
  * - `metered` — per-token billing against the owner's account. Legal to
@@ -165,7 +165,7 @@ declare function backendDescriptor(id: BackendId): BackendDescriptor;
165
165
  * an act by the machine's owner against their own account, and the threat
166
166
  * model here is a hostile *job*, not an owner routing around a rule that
167
167
  * exists to protect them. What this catches is the accident — a remote paid
168
- * endpoint offered `public` because nobody thought about the bill. See
168
+ * endpoint offered to a team because nobody thought about the bill. See
169
169
  * `docs/security.md` §4a.
170
170
  */
171
171
  declare function isLocalHost(hostname: string): boolean;
@@ -270,54 +270,53 @@ declare function classifyCost(id: BackendId, baseUrl: string | undefined, model:
270
270
  * Who may run a job, declared by the app that enqueued it.
271
271
  *
272
272
  * - `private` — only the job owner's own devices.
273
- * - `team` — a device whose owner has this person on their roster.
274
- * - `public` — any device offering `public` compute.
273
+ * - `team` — a device whose owner admits this person.
275
274
  *
276
275
  * **One vocabulary, ruled 2026-08-24.** These were `self | named | public`
277
- * while {@link OfferScope} became `private | team | public`, which would have
278
- * left every seam where the two meet speaking two languages for one idea, and
279
- * every doc explaining "self versus private" for ever. They are still
280
- * independent axes — a job says who may run it, a service says who it will run
281
- * for — and a job runs only where both agree
282
- * ({@link MUSTS.AUDIENCE_BOTH_SIDES}). Sharing the words costs nothing and
283
- * saves a mapping layer nobody would have enjoyed maintaining.
276
+ * while {@link OfferScope} used different words for the same idea, which would
277
+ * have left every seam where the two meet speaking two languages, and every
278
+ * doc explaining "self versus private" for ever. They are still independent
279
+ * axes — a job says who may run it, a service says who it will run for — and a
280
+ * job runs only where both agree ({@link MUSTS.AUDIENCE_BOTH_SIDES}).
281
+ *
282
+ * **`public` is gone, ruled 2026-08-26 (byollm_016).** Not deprecated,
283
+ * removed, and removed from the OSS daemon too rather than parked as a
284
+ * community posture. The argument was a measurement rather than a preference:
285
+ * device-side admission had never once been exercised end to end, because
286
+ * every cross-user test ran against a publicly offered service and
287
+ * {@link matchAudience} returned ALLOWED for those *without consulting the
288
+ * device at all*. `public` was the off switch for admission, and an enum with
289
+ * a value that skips verification is a fail-open waiting for the wiring bug
290
+ * that reaches it. There is now no such value.
284
291
  */
285
292
  declare const Audience: z.ZodEnum<{
286
293
  private: "private";
287
294
  team: "team";
288
- public: "public";
289
295
  }>;
290
296
  type Audience = z.infer<typeof Audience>;
291
297
  /**
292
298
  * What a device's owner is willing to run for other people, per service.
293
299
  *
294
300
  * - `private` — the owner's own work only.
295
- * - `team` — the owner's roster. Membership is **central**, not per-person:
296
- * the device follows the roster rather than holding its own copy of who is
297
- * in it (byollm_016, 2026-08-24).
298
- * - `public` — any job, from anyone. This is the community posture the daemon
299
- * has always had (`byollm offer <service> public`), bounded by community
300
- * budgets. byollm_016 parks it as a **hosted-product** surface the cloud
301
- * dashboard does not offer it which is not the same as removing it from
302
- * the daemon, and the CLI still accepts it.
303
- *
304
- * Deliberately *not* the same words as {@link Audience}, which they used to
305
- * share. They are independent axes — a job says who may run it, a service says
306
- * who it will run for — and identical spellings made that read as one concept
307
- * with two homes. A job runs only where both agree
308
- * ({@link MUSTS.AUDIENCE_BOTH_SIDES}); {@link matches} is the one place the
309
- * correspondence lives.
301
+ * - `team` — whoever the owner's authority admits. Membership is **central**,
302
+ * not per-person: the device follows what it is told by a signature it can
303
+ * check, rather than holding its own copy of who is in it (byollm_016).
304
+ *
305
+ * Two values, and no third that means "everyone". See {@link Audience} for
306
+ * why `public` was removed rather than parked, and note the shape of the
307
+ * remaining enum: **every value left requires the device to verify
308
+ * something.** `private` checks the owner; `team` checks admission. That is
309
+ * the property, not an accident of there being two.
310
310
  */
311
311
  declare const OfferScope: z.ZodEnum<{
312
312
  private: "private";
313
313
  team: "team";
314
- public: "public";
315
314
  }>;
316
315
  type OfferScope = z.infer<typeof OfferScope>;
317
316
  /** All audience values, in widening order. */
318
- declare const AUDIENCES: readonly ("private" | "team" | "public")[];
317
+ declare const AUDIENCES: readonly ("private" | "team")[];
319
318
  /** All offer scopes, in widening order. */
320
- declare const OFFER_SCOPES: readonly ("private" | "team" | "public")[];
319
+ declare const OFFER_SCOPES: readonly ("private" | "team")[];
321
320
  /**
322
321
  * Why a job was refused. Distinct codes because byollm_002 requires that
323
322
  * different truths never share a message — "no matching work" and "refused on
@@ -356,7 +355,7 @@ interface SpendConsent {
356
355
  * its matcher call, so no code path can observe a scope wider than the cost
357
356
  * class allows:
358
357
  *
359
- * - `subscription` is locked to `self` regardless of config
358
+ * - `subscription` is locked to `private` regardless of config
360
359
  * ({@link MUSTS.SUBSCRIPTION_SELF_LOCK}) — someone else's terms.
361
360
  * - `metered` narrows to `private` unless the owner has explicitly acknowledged
362
361
  * the spend ({@link MUSTS.METERED_DEFAULTS_SELF}) — their money.
@@ -374,7 +373,8 @@ interface MatchJob {
374
373
  readonly audience: Audience;
375
374
  /**
376
375
  * Optional server-side restriction on which runner owners may take a
377
- * `named` job. Defence in depth only the daemon's local allowlist is the
376
+ * `team` job. Defence in depth only, and direct-mode only it never
377
+ * reaches a daemon (cloud_008 §0.2), so the device's own admission is the
378
378
  * enforcing side ({@link MUSTS.NAMED_LOCAL_ALLOWLIST}).
379
379
  */
380
380
  readonly audienceAllow?: readonly string[] | undefined;
@@ -390,13 +390,24 @@ interface MatchDaemon {
390
390
  /** What the owner agreed to spend on others, for a `metered` backend. */
391
391
  readonly spend?: SpendConsent | undefined;
392
392
  /**
393
- * Does this daemon's *local* allowlist admit the given owner for the server
394
- * origin the job came from? Supplied as a predicate so the protocol package
395
- * stays free of file I/O; the daemon passes its allowlist, the server
396
- * passes a conservative `() => true` because it cannot know a remote
397
- * daemon's local list and must not pretend to.
393
+ * Has something **this device verified** admitted the job's owner?
394
+ *
395
+ * A predicate rather than a value so the protocol package stays free of
396
+ * both file I/O and signature state. What supplies it has changed twice and
397
+ * will change again — a local allowlist, then a held roster, and now a
398
+ * claim-time signed grant (Amendment J) — and the law it feeds has not
399
+ * changed at all: a `team` service runs a stranger's work only when
400
+ * somebody this device can check said so.
401
+ *
402
+ * The server passes a conservative `() => true`: it cannot know what a
403
+ * remote device verified and must not pretend to. The device is the
404
+ * enforcing side, which is the whole point of asking here.
405
+ *
406
+ * Named for the question, not for where the answer lives. This was called
407
+ * `locallyAllows`, and "locally" stopped being true the moment the answer
408
+ * came from a document somebody else signed.
398
409
  */
399
- readonly locallyAllows: (owner: string) => boolean;
410
+ readonly admits: (owner: string) => boolean;
400
411
  }
401
412
  /**
402
413
  * Decide whether a job may run on a daemon.
@@ -405,8 +416,8 @@ interface MatchDaemon {
405
416
  * 1. the job's audience must admit the daemon's owner, and
406
417
  * 2. the backend's offer scope must admit the job's owner.
407
418
  *
408
- * The full nine-way matrix (three audiences × three offer scopes) is asserted
409
- * by the conformance kit. The function is pure and total so both the daemon
419
+ * The full four-way matrix (two audiences × two offer scopes) is asserted by
420
+ * the conformance kit. The function is pure and total so both the daemon
410
421
  * and the server can run the identical rule — the daemon refuses, and the
411
422
  * server refuses too (byollm_003 §Server-side MUSTs).
412
423
  *
@@ -418,7 +429,7 @@ interface MatchDaemon {
418
429
  * owner: "bob",
419
430
  * offerScope: "team",
420
431
  * cost: "free",
421
- * locallyAllows: (o) => o === "alice",
432
+ * admits: (o) => o === "alice",
422
433
  * },
423
434
  * );
424
435
  * // result.ok === true
@@ -443,9 +454,9 @@ declare const REFUSAL_MESSAGES: Readonly<Record<MatchRefusal, string>>;
443
454
  * per-field limits were real and the aggregate one was a number in a frozen
444
455
  * object.
445
456
  *
446
- * byollm_004 §4 requires stricter limits for community (`named`/`public`)
447
- * jobs; those are applied on top of these by the daemon's budget check, which
448
- * knows the job's audience. These are the absolute ceilings for any job.
457
+ * byollm_004 §4 requires stricter limits for community (`team`) jobs; those
458
+ * are applied on top of these by the daemon's budget check, which knows the
459
+ * job's audience. These are the absolute ceilings for any job.
449
460
  */
450
461
  declare const PAYLOAD_LIMITS: Readonly<{
451
462
  /** Max characters in any single text field. */
@@ -466,7 +477,7 @@ declare const ChatMessage: z.ZodObject<{
466
477
  assistant: "assistant";
467
478
  }>;
468
479
  content: z.ZodString;
469
- }, z.core.$strip>;
480
+ }, z.core.$strict>;
470
481
  type ChatMessage = z.infer<typeof ChatMessage>;
471
482
  /**
472
483
  * Payload for `llm.generate`.
@@ -493,7 +504,7 @@ declare const ChatPayload: z.ZodObject<{
493
504
  assistant: "assistant";
494
505
  }>;
495
506
  content: z.ZodString;
496
- }, z.core.$strip>>;
507
+ }, z.core.$strict>>;
497
508
  system: z.ZodOptional<z.ZodString>;
498
509
  }, z.core.$strict>;
499
510
  type ChatPayload = z.infer<typeof ChatPayload>;
@@ -520,7 +531,7 @@ declare const KindedPayload: z.ZodDiscriminatedUnion<[z.ZodObject<{
520
531
  prompt: z.ZodString;
521
532
  system: z.ZodOptional<z.ZodString>;
522
533
  }, z.core.$strict>;
523
- }, z.core.$strip>, z.ZodObject<{
534
+ }, z.core.$strict>, z.ZodObject<{
524
535
  kind: z.ZodLiteral<"llm.chat">;
525
536
  payload: z.ZodObject<{
526
537
  messages: z.ZodArray<z.ZodObject<{
@@ -530,10 +541,10 @@ declare const KindedPayload: z.ZodDiscriminatedUnion<[z.ZodObject<{
530
541
  assistant: "assistant";
531
542
  }>;
532
543
  content: z.ZodString;
533
- }, z.core.$strip>>;
544
+ }, z.core.$strict>>;
534
545
  system: z.ZodOptional<z.ZodString>;
535
546
  }, z.core.$strict>;
536
- }, z.core.$strip>], "kind">;
547
+ }, z.core.$strict>], "kind">;
537
548
  type KindedPayload = z.infer<typeof KindedPayload>;
538
549
  /** The payload type for a given kind. */
539
550
  type PayloadFor<K extends JobKind> = K extends "llm.generate" ? GeneratePayload : ChatPayload;
@@ -562,11 +573,11 @@ declare function payloadTextLength(kinded: KindedPayload): number;
562
573
  declare const JobState: z.ZodEnum<{
563
574
  ok: "ok";
564
575
  error: "error";
576
+ expired: "expired";
565
577
  queued: "queued";
566
578
  claimed: "claimed";
567
579
  running: "running";
568
580
  canceled: "canceled";
569
- expired: "expired";
570
581
  }>;
571
582
  type JobState = z.infer<typeof JobState>;
572
583
  /** States from which a job never moves again. */
@@ -580,7 +591,7 @@ declare const Lease: z.ZodObject<{
580
591
  id: z.ZodString;
581
592
  runnerId: z.ZodString;
582
593
  expiresAt: z.ZodNumber;
583
- }, z.core.$strip>;
594
+ }, z.core.$strict>;
584
595
  type Lease = z.infer<typeof Lease>;
585
596
  /** Payload union as it appears on a job record. */
586
597
  declare const JobPayload: z.ZodUnion<readonly [z.ZodObject<{
@@ -594,7 +605,7 @@ declare const JobPayload: z.ZodUnion<readonly [z.ZodObject<{
594
605
  assistant: "assistant";
595
606
  }>;
596
607
  content: z.ZodString;
597
- }, z.core.$strip>>;
608
+ }, z.core.$strict>>;
598
609
  system: z.ZodOptional<z.ZodString>;
599
610
  }, z.core.$strict>]>;
600
611
  type JobPayload = z.infer<typeof JobPayload>;
@@ -623,13 +634,12 @@ declare const ClaimedJob: z.ZodObject<{
623
634
  assistant: "assistant";
624
635
  }>;
625
636
  content: z.ZodString;
626
- }, z.core.$strip>>;
637
+ }, z.core.$strict>>;
627
638
  system: z.ZodOptional<z.ZodString>;
628
639
  }, z.core.$strict>]>;
629
640
  audience: z.ZodEnum<{
630
641
  private: "private";
631
642
  team: "team";
632
- public: "public";
633
643
  }>;
634
644
  owner: z.ZodString;
635
645
  site: z.ZodOptional<z.ZodString>;
@@ -638,13 +648,13 @@ declare const ClaimedJob: z.ZodObject<{
638
648
  id: z.ZodString;
639
649
  runnerId: z.ZodString;
640
650
  expiresAt: z.ZodNumber;
641
- }, z.core.$strip>;
651
+ }, z.core.$strict>;
642
652
  }, z.core.$strict>;
643
653
  type ClaimedJob = z.infer<typeof ClaimedJob>;
644
654
  /**
645
655
  * The provenance that travels with every result to the delivery seam.
646
656
  *
647
- * byollm_003 Rev 1: a `named`/`public` result is attacker-controlled text.
657
+ * byollm_003 Rev 1: a `team` result is attacker-controlled text.
648
658
  * The app must never render volunteer output as its own AI's answer without
649
659
  * knowing that is what it is ({@link MUSTS.PROVENANCE_NAMES_DEVICE}).
650
660
  */
@@ -652,7 +662,6 @@ declare const ResultProvenance: z.ZodObject<{
652
662
  audience: z.ZodEnum<{
653
663
  private: "private";
654
664
  team: "team";
655
- public: "public";
656
665
  }>;
657
666
  runnerId: z.ZodString;
658
667
  runnerOwner: z.ZodString;
@@ -744,7 +753,6 @@ type JobOutcome = z.infer<typeof JobOutcome>;
744
753
  * list rather than three private vocabularies.
745
754
  */
746
755
  declare const RefusalReason: z.ZodEnum<{
747
- "select-unavailable": "select-unavailable";
748
756
  "default-ambiguity": "default-ambiguity";
749
757
  "default-unusable": "default-unusable";
750
758
  }>;
@@ -774,7 +782,6 @@ type RefusalReason = z.infer<typeof RefusalReason>;
774
782
  declare const JobRefused: z.ZodObject<{
775
783
  outcome: z.ZodLiteral<"refused">;
776
784
  reason: z.ZodEnum<{
777
- "select-unavailable": "select-unavailable";
778
785
  "default-ambiguity": "default-ambiguity";
779
786
  "default-unusable": "default-unusable";
780
787
  }>;
@@ -818,11 +825,11 @@ declare const DeliveredResult: z.ZodObject<{
818
825
  state: z.ZodEnum<{
819
826
  ok: "ok";
820
827
  error: "error";
828
+ expired: "expired";
821
829
  queued: "queued";
822
830
  claimed: "claimed";
823
831
  running: "running";
824
832
  canceled: "canceled";
825
- expired: "expired";
826
833
  }>;
827
834
  outcome: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
828
835
  outcome: z.ZodLiteral<"ok">;
@@ -840,7 +847,6 @@ declare const DeliveredResult: z.ZodObject<{
840
847
  audience: z.ZodEnum<{
841
848
  private: "private";
842
849
  team: "team";
843
- public: "public";
844
850
  }>;
845
851
  runnerId: z.ZodString;
846
852
  runnerOwner: z.ZodString;
@@ -919,9 +925,8 @@ declare const JobStub: z.ZodObject<{
919
925
  audience: z.ZodEnum<{
920
926
  private: "private";
921
927
  team: "team";
922
- public: "public";
923
928
  }>;
924
- service: z.ZodOptional<z.ZodString>;
929
+ purpose: z.ZodOptional<z.ZodString>;
925
930
  sizeClass: z.ZodEnum<{
926
931
  small: "small";
927
932
  medium: "medium";
@@ -932,7 +937,23 @@ declare const JobStub: z.ZodObject<{
932
937
  deadlineAt: z.ZodNumber;
933
938
  }, z.core.$strict>;
934
939
  type JobStub = z.infer<typeof JobStub>;
935
- /** A stub, plus the lease the claiming runner now holds for it. */
940
+ /**
941
+ * A stub, plus the lease the claiming runner now holds for it — and, on a
942
+ * relayed route, the grant that says it may run at all.
943
+ *
944
+ * The grant lives here rather than on {@link JobStub} because of *when* it is
945
+ * authored. A stub exists from enqueue; a grant is written at claim, against
946
+ * the membership and mapping true at that moment. That timing is the whole of
947
+ * Amendment J: a job queued yesterday for somebody removed this morning gets
948
+ * no grant when it is finally claimed, and a roster held on the device could
949
+ * never have known.
950
+ *
951
+ * Optional, and the absence is meaningful rather than lenient. A device that
952
+ * pinned a control-plane key at pairing **requires** one — a claimed job
953
+ * arriving without it is refused, not admitted by default. A device that
954
+ * pinned none is in direct mode, where there is no control plane to author
955
+ * anything and the owner's own work is the only work that runs.
956
+ */
936
957
  declare const ClaimedStub: z.ZodObject<{
937
958
  id: z.ZodString;
938
959
  kind: z.ZodEnum<{
@@ -944,9 +965,8 @@ declare const ClaimedStub: z.ZodObject<{
944
965
  audience: z.ZodEnum<{
945
966
  private: "private";
946
967
  team: "team";
947
- public: "public";
948
968
  }>;
949
- service: z.ZodOptional<z.ZodString>;
969
+ purpose: z.ZodOptional<z.ZodString>;
950
970
  sizeClass: z.ZodEnum<{
951
971
  small: "small";
952
972
  medium: "medium";
@@ -959,7 +979,19 @@ declare const ClaimedStub: z.ZodObject<{
959
979
  id: z.ZodString;
960
980
  runnerId: z.ZodString;
961
981
  expiresAt: z.ZodNumber;
962
- }, z.core.$strip>;
982
+ }, z.core.$strict>;
983
+ grant: z.ZodOptional<z.ZodObject<{
984
+ grantId: z.ZodString;
985
+ jobId: z.ZodString;
986
+ site: z.ZodString;
987
+ user: z.ZodString;
988
+ owner: z.ZodString;
989
+ purpose: z.ZodString;
990
+ kind: z.ZodString;
991
+ service: z.ZodString;
992
+ issuedAt: z.ZodNumber;
993
+ signature: z.ZodString;
994
+ }, z.core.$strict>>;
963
995
  }, z.core.$strict>;
964
996
  type ClaimedStub = z.infer<typeof ClaimedStub>;
965
997
 
@@ -1297,105 +1329,270 @@ declare function verifyRequest(input: {
1297
1329
  }): SignatureFailure | null;
1298
1330
 
1299
1331
  /**
1300
- * The roster a daemon holds, and how it knows the roster is real.
1332
+ * What a site says it needs byollm_016 Amendment L.
1333
+ *
1334
+ * A site declares **purposes**, and each purpose lists the job kinds it uses.
1335
+ * A person then maps each purpose to one of their own services, on the consent
1336
+ * screen, and that mapping *is* the consent. The control plane joins the two
1337
+ * at claim time and signs the result into a grant.
1338
+ *
1339
+ * ## Why a site declares needs instead of naming services
1340
+ *
1341
+ * Because it cannot name one. The site's vocabulary is its own purposes; the
1342
+ * person's vocabulary is their services; and the two never meet. A site asks
1343
+ * for "writing assistant, llm.chat" and learns only whether that slot is
1344
+ * satisfiable — never which model answered, never whose machine, never even
1345
+ * the name of the service. Key-vs-value reaches its strongest form here: the
1346
+ * site cannot describe what it wants *or* name it, only ask for what it
1347
+ * declared.
1348
+ *
1349
+ * ## Keys are ids; labels are prose
1350
+ *
1351
+ * They are separate fields and nothing derives one from the other, which is
1352
+ * the amendment's ruling and worth restating where somebody will read it. A
1353
+ * key travels on every job and is what mappings are stored against, so it is
1354
+ * stable-or-nothing: renaming one deletes a purpose and creates another,
1355
+ * unmapping everybody who had chosen for it. A label is changeable whenever
1356
+ * the site likes and is the **only** thing a consent screen renders.
1357
+ */
1358
+ /**
1359
+ * The purpose a site gets when it declares no purposes of its own.
1360
+ *
1361
+ * Reserved, and refused by {@link Manifest} rather than by whatever handles
1362
+ * registration. A site with a single undifferentiated use has one purpose —
1363
+ * everything it does — and that purpose needs an id because mappings are
1364
+ * keyed by one. An id taken from the site's own vocabulary would collide the
1365
+ * day it declared a real purpose of the same name.
1366
+ *
1367
+ * **Never rendered.** "default → your Claude" tells a person nothing; a
1368
+ * consent screen shows the site's own name for this slot, because that is
1369
+ * what a single-purpose site's one purpose actually is.
1370
+ */
1371
+ declare const RESERVED_PURPOSE = "default";
1372
+ declare const Purpose: z.ZodObject<{
1373
+ label: z.ZodString;
1374
+ description: z.ZodOptional<z.ZodString>;
1375
+ kinds: z.ZodArray<z.ZodEnum<{
1376
+ "llm.generate": "llm.generate";
1377
+ "llm.chat": "llm.chat";
1378
+ }>>;
1379
+ }, z.core.$strict>;
1380
+ type Purpose = z.infer<typeof Purpose>;
1381
+ declare const Manifest: z.ZodRecord<z.ZodString, z.ZodObject<{
1382
+ label: z.ZodString;
1383
+ description: z.ZodOptional<z.ZodString>;
1384
+ kinds: z.ZodArray<z.ZodEnum<{
1385
+ "llm.generate": "llm.generate";
1386
+ "llm.chat": "llm.chat";
1387
+ }>>;
1388
+ }, z.core.$strict>>;
1389
+ type Manifest = z.infer<typeof Manifest>;
1390
+ /**
1391
+ * The manifest a site with no declared purposes is treated as having.
1392
+ *
1393
+ * The sugar in Amendment L, made explicit rather than special-cased
1394
+ * downstream: everything after this point sees a manifest with one purpose,
1395
+ * so no consent screen, mapping table or resolver needs a branch for the
1396
+ * flat-list case.
1397
+ *
1398
+ * The label is the caller's — a site's own name — because it is the one thing
1399
+ * that can make "everything this site does" read as a sentence about a
1400
+ * particular site rather than about software in general.
1401
+ */
1402
+ declare function singlePurposeManifest(input: {
1403
+ readonly label: string;
1404
+ readonly kinds: readonly JobKind[];
1405
+ }): Manifest;
1406
+
1407
+ /**
1408
+ * One job, one signature, one answer — byollm_016 Amendment J.
1409
+ *
1410
+ * A grant is the control plane's signed statement that a particular job may
1411
+ * run on a particular device, authored at claim time and verified against the
1412
+ * key that device pinned when it paired.
1413
+ *
1414
+ * ## What it replaced, and why the replacement is smaller
1415
+ *
1416
+ * Until 2026-08-26 a device held a signed **roster** and answered admission
1417
+ * from it. Amendment G's four properties were right and the mechanism was a
1418
+ * cache — one that bought nothing. On the cloud route the job path and the
1419
+ * roster path share fate: jobs arrive through the relay, so if the relay is
1420
+ * unreachable there are no jobs to admit and a locally held roster adds no
1421
+ * availability. What it did add was staleness, which is the only reason
1422
+ * `ROSTER_MAX_AGE_MS` existed: a bound on how long a removed person keeps
1423
+ * running. Authoring at claim collapses that bound to this document's own
1424
+ * lifetime — add somebody and their next job runs, remove them and their next
1425
+ * claim fails, including jobs already queued.
1426
+ *
1427
+ * It also collapses four questions into one signature. Consented, member,
1428
+ * admitted, and *which service* were four mechanisms answering separately;
1429
+ * they are now four fields of one statement, and the device verifies once.
1301
1430
  *
1302
- * byollm_001 Amendment G, RATIFIED 2026-08-25. A `team` job is admitted by a
1303
- * list **this device holds**, signed by the owner's control plane and verified
1304
- * against a key pinned at pairing — never by an assertion from the party
1305
- * routing the job, per-job or in bulk.
1431
+ * ## What it is not
1306
1432
  *
1307
- * The relay's power over this is exactly denial: it can withhold a roster as
1308
- * it can withhold a job, and it can forge neither. That is what lets the hub
1309
- * go on reading and filtering rosters for its own routing without being
1310
- * trusted for admission non-authorship, not blindness.
1433
+ * Amendment G property 1 outlawed admitting on a per-job assertion, and this
1434
+ * is per-job. The distinction is authorship: G outlawed trusting the
1435
+ * **relay's or site's unsigned** claim. A grant is signed by the control
1436
+ * plane with a key the device pinned at pairing, so the relay can withhold it
1437
+ * and cannot forge it — exactly the power a relay has over a job.
1438
+ * `RELAY_BLIND` is untouched: the relay delivers, it never authors.
1439
+ *
1440
+ * ## What the device still checks for itself
1441
+ *
1442
+ * A grant is necessary and not sufficient. Four checks stay on the device and
1443
+ * none of them is delegated:
1444
+ *
1445
+ * 1. the signature, against the pinned key;
1446
+ * 2. replay — {@link SignedGrant.grantId} is single-use;
1447
+ * 3. offer-consistency — the named service is one this device actually
1448
+ * offers, at a scope that includes this user;
1449
+ * 4. **private is absolute** — a `private` service runs for the paired owner
1450
+ * and nobody else, so no compromise of a control plane can grant somebody
1451
+ * else's job onto it.
1311
1452
  */
1312
1453
  /**
1313
- * How old a held roster may be before a device stops honouring it.
1454
+ * How long a grant is honoured after it was signed. Ruled 120s (2026-08-26).
1314
1455
  *
1315
- * One hour, and the shortest constant in this protocol on purpose: every other
1316
- * one bounds how long a *thing* stays valid, and this one alone bounds how
1317
- * long a *person* keeps access after the owner has said no.
1456
+ * This bounds **acceptance**, not execution: a job admitted inside the window
1457
+ * runs to completion however long it takes. So the number only has to cover
1458
+ * the trip from the control plane signing to the device checking claim,
1459
+ * deliver, verify — and every second past that is a second a captured grant
1460
+ * stays useful.
1318
1461
  *
1319
- * A failure bound, not a sync interval. A daemon refreshes on every heartbeat
1320
- * and a removal propagates in seconds; the hour is what a device gets when
1321
- * that conversation stops working enough that a closed laptop or a flaky
1322
- * café network does not narrow a working device, and not so much that a
1323
- * removed teammate outlives the owner's patience.
1462
+ * Two minutes is generous for that trip and mean for the capture. It is also
1463
+ * the number ordinary clock drift is measured against, which is why
1464
+ * {@link CLOCK_SKEW_WARN_MS} sits well inside it: a device whose clock is off
1465
+ * by half the window would refuse real work, and must be told before it does.
1466
+ *
1467
+ * The verifier's policy, deliberately not a field on the document. An
1468
+ * `expiresAt` the signer chose would let whoever signs decide how long their
1469
+ * own statement stays good, and the party with the most reason to want a
1470
+ * longer window is the party being bounded.
1324
1471
  */
1325
- declare const ROSTER_MAX_AGE_MS: number;
1472
+ declare const GRANT_MAX_AGE_MS = 120000;
1326
1473
  /**
1327
- * The domain separator, and why a roster gets its own.
1474
+ * Clock disagreement past which a device says so, before it starts refusing.
1475
+ *
1476
+ * Skew eats {@link GRANT_MAX_AGE_MS} directly — a device 60s behind its
1477
+ * relay's clock has half a window left, and one 120s behind has none and
1478
+ * refuses everything for a reason no refusal message would otherwise name.
1479
+ * Thirty seconds is a quarter of the window: far enough out to be a real
1480
+ * problem, early enough to be a warning rather than an outage.
1481
+ */
1482
+ declare const CLOCK_SKEW_WARN_MS = 30000;
1483
+ /**
1484
+ * Skew past which a freshness refusal names the clock instead of the grant.
1485
+ *
1486
+ * Five seconds, because below that the clock is not the story and saying so
1487
+ * would send somebody to check ntp about an unrelated failure. Above it, "this
1488
+ * grant expired" and "your clock is wrong" are the same event wearing
1489
+ * different words, and only one of them can be acted on.
1490
+ */
1491
+ declare const CLOCK_ATTRIBUTION_MS = 5000;
1492
+ /**
1493
+ * The domain separator.
1328
1494
  *
1329
1495
  * Every signature in this system says what kind of statement it is before it
1330
- * says anything else. Without that, bytes signed for one purpose verify for
1331
- * another: a roster document and a request body are both "some bytes this key
1332
- * signed", and a scheme that could not tell them apart would let a captured
1333
- * roster be replayed as a request — or worse, let a control plane that signs
1334
- * one thing be held to have signed the other.
1335
- */
1336
- declare const ROSTER_CONTEXT = "byollm/v1/roster";
1337
- declare const SignedRoster: z.ZodObject<{
1496
+ * says anything else. Without it, bytes signed for one purpose verify for
1497
+ * another a grant and a request are both "bytes this key signed", and a
1498
+ * scheme that could not tell them apart would let one be replayed as the
1499
+ * other.
1500
+ */
1501
+ declare const GRANT_CONTEXT = "byollm/v1/grant";
1502
+ declare const SignedGrant: z.ZodObject<{
1503
+ grantId: z.ZodString;
1504
+ jobId: z.ZodString;
1505
+ site: z.ZodString;
1506
+ user: z.ZodString;
1338
1507
  owner: z.ZodString;
1339
- members: z.ZodArray<z.ZodString>;
1508
+ purpose: z.ZodString;
1509
+ kind: z.ZodString;
1510
+ service: z.ZodString;
1340
1511
  issuedAt: z.ZodNumber;
1341
1512
  signature: z.ZodString;
1342
1513
  }, z.core.$strict>;
1343
- type SignedRoster = z.infer<typeof SignedRoster>;
1514
+ type SignedGrant = z.infer<typeof SignedGrant>;
1515
+ /** Everything a grant says, before it is signed. */
1516
+ type GrantClaims = Omit<SignedGrant, "signature">;
1517
+ /**
1518
+ * Every field of {@link SignedGrant} except the signature, sorted.
1519
+ *
1520
+ * **Derived from the schema, never written out by hand.** The unsigned-field
1521
+ * attack is that somebody adds a field to the document, forgets to add it to
1522
+ * the bytes, and ships a value an intermediary can rewrite without breaking
1523
+ * any signature. A hand-maintained list is exactly the shape that fails: it
1524
+ * does not grow when the code does, and nothing about adding a field reminds
1525
+ * you it exists.
1526
+ *
1527
+ * Reading the shape closes it structurally rather than by review. A new field
1528
+ * is signed the moment it is declared, and grant.test.ts asserts this list
1529
+ * still covers the schema so a future zod version that hides `shape` fails
1530
+ * loudly instead of silently signing less.
1531
+ */
1532
+ declare const GRANT_SIGNED_FIELDS: readonly (keyof GrantClaims)[];
1344
1533
  /**
1345
1534
  * The exact bytes both sides sign and verify.
1346
1535
  *
1347
- * Every field that decides what the roster *means* is in here. Leave one out
1348
- * and it becomes something an intermediary can change without breaking the
1349
- * signature `owner` most of all: a roster whose owner was not signed over
1350
- * could be lifted from one account and delivered to another's devices, and
1351
- * every signature check would pass.
1536
+ * JSON-encoded rather than joined with a separator, because a separator can
1537
+ * be imitated. Newline-joining `["a", "b\nc"]` and `["a\nb", "c"]` produces
1538
+ * identical bytes, so two different grants would share a signature and the
1539
+ * values here include a site id and a user id, at least one of which comes
1540
+ * from somebody else's namespace. JSON escapes the separator it uses, so no
1541
+ * arrangement of field values can spell a different document.
1352
1542
  *
1353
- * Members are joined with NUL, which cannot appear in an id, so no arrangement
1354
- * of member names can imitate a different membership. Joining on a comma would
1355
- * let `["a,b"]` and `["a","b"]` sign identically.
1543
+ * The context string leads, and the field order is the schema's own sorted
1544
+ * keys, so the encoding is canonical without anyone maintaining a list.
1356
1545
  */
1357
- declare function rosterStatement(input: {
1358
- owner: string;
1359
- members: readonly string[];
1360
- issuedAt: number;
1361
- }): Uint8Array;
1362
- /** Sign a roster with the control plane's own key. */
1363
- declare function signRoster(keys: Pick<StoredKeys, "identityPrivate">, input: {
1364
- owner: string;
1365
- members: readonly string[];
1366
- issuedAt: number;
1367
- }): SignedRoster;
1368
- /** Why a roster was refused. Typed for logs; never returned to a caller. */
1369
- type RosterRefusal = "bad-signature" | "wrong-owner" | "stale" | "from-the-future"
1546
+ declare function grantStatement(claims: GrantClaims): Uint8Array;
1547
+ /** Sign a grant with the control plane's own key. */
1548
+ declare function signGrant(keys: Pick<StoredKeys, "identityPrivate">, claims: GrantClaims): SignedGrant;
1370
1549
  /**
1371
- * A roster arrived and this device pinned no key to check it against.
1550
+ * Why a grant was refused.
1551
+ *
1552
+ * Split by remedy, because these send somebody to different places: fix your
1553
+ * clock, take it up with the relay, or nothing at all — you are being
1554
+ * attacked and the refusal worked.
1372
1555
  *
1373
- * Not a bad signature nothing was checked. It is the one refusal that is
1374
- * evidence *about the pairing* rather than about the document: an upstream
1375
- * that sends rosters has a control plane, so a device holding no key from
1376
- * it paired before roster sync existed and can never verify one. The remedy
1377
- * is re-pairing, and this is the only refusal here that has one.
1556
+ * There is deliberately no `no-pinned-key` here. A device that pinned no
1557
+ * control-plane key never reaches this function: it is in direct mode, and
1558
+ * the question "is this grant good" does not arise. A value nothing can
1559
+ * return is a branch every caller has to handle and no test can reach.
1378
1560
  */
1379
- | "no-pinned-key";
1561
+ type GrantRefusal =
1562
+ /** The signature does not verify against the pinned key. */
1563
+ "bad-signature"
1564
+ /** Genuine, and for a different device's owner. */
1565
+ | "wrong-owner"
1566
+ /** Genuine, and lifted from a different job. */
1567
+ | "wrong-job"
1568
+ /** Older than {@link GRANT_MAX_AGE_MS}. */
1569
+ | "expired"
1380
1570
  /**
1381
- * Is this roster one this device may admit people from, right now?
1571
+ * Issued further in the future than clock drift explains.
1382
1572
  *
1383
- * `owner` is passed in rather than read out of the document, for the reason
1384
- * {@link verifyLink} takes its successor as an argument: a verifier that
1385
- * recovered the owner from the signed bytes would accept a genuine roster
1386
- * belonging to somebody else, and every check would pass.
1573
+ * Checked, and not as pedantry: an `issuedAt` ahead of now extends a
1574
+ * grant's life past the bound, which is the whole thing being enforced.
1575
+ *
1576
+ * Tolerant by {@link CLOCK_SKEW_WARN_MS}, because it was tolerant by
1577
+ * nothing and that made ordinary drift a total outage — see
1578
+ * {@link verifyGrant}.
1579
+ */
1580
+ | "from-the-future";
1581
+ /**
1582
+ * Is this grant one this device may act on, right now?
1387
1583
  *
1388
- * Age is checked in **both** directions. A clock far ahead is as much a
1389
- * problem as one behind: an `issuedAt` in the future would extend a roster's
1390
- * life past the bound, which is the whole thing being enforced.
1584
+ * Document-level checks only. Replay, offer-consistency and the private rule
1585
+ * need state this function does not have and are the device's to apply see
1586
+ * the class comment for the full list of four.
1391
1587
  */
1392
- declare function verifyRoster(input: {
1393
- roster: SignedRoster;
1588
+ declare function verifyGrant(input: {
1589
+ grant: SignedGrant;
1394
1590
  owner: string;
1591
+ jobId: string;
1395
1592
  controlPlanePublic: string;
1396
1593
  now: number;
1397
1594
  maxAgeMs?: number;
1398
- }): RosterRefusal | null;
1595
+ }): GrantRefusal | null;
1399
1596
 
1400
1597
  /**
1401
1598
  * Rotation — byollm_009 Amendment C.
@@ -1762,7 +1959,6 @@ declare const Capability: z.ZodObject<{
1762
1959
  "llm.chat": "llm.chat";
1763
1960
  }>;
1764
1961
  service: z.ZodString;
1765
- isDefault: z.ZodBoolean;
1766
1962
  backendId: z.ZodEnum<{
1767
1963
  ollama: "ollama";
1768
1964
  mlx: "mlx";
@@ -1792,7 +1988,6 @@ declare const Capability: z.ZodObject<{
1792
1988
  offerScope: z.ZodEnum<{
1793
1989
  private: "private";
1794
1990
  team: "team";
1795
- public: "public";
1796
1991
  }>;
1797
1992
  }, z.core.$strict>;
1798
1993
  type Capability = z.infer<typeof Capability>;
@@ -1803,7 +1998,6 @@ declare const CapabilityMatrix: z.ZodArray<z.ZodObject<{
1803
1998
  "llm.chat": "llm.chat";
1804
1999
  }>;
1805
2000
  service: z.ZodString;
1806
- isDefault: z.ZodBoolean;
1807
2001
  backendId: z.ZodEnum<{
1808
2002
  ollama: "ollama";
1809
2003
  mlx: "mlx";
@@ -1833,7 +2027,6 @@ declare const CapabilityMatrix: z.ZodArray<z.ZodObject<{
1833
2027
  offerScope: z.ZodEnum<{
1834
2028
  private: "private";
1835
2029
  team: "team";
1836
- public: "public";
1837
2030
  }>;
1838
2031
  }, z.core.$strict>>;
1839
2032
  type CapabilityMatrix = z.infer<typeof CapabilityMatrix>;
@@ -1861,11 +2054,26 @@ declare const WithheldKind: z.ZodObject<{
1861
2054
  offer: z.ZodEnum<{
1862
2055
  private: "private";
1863
2056
  team: "team";
1864
- public: "public";
1865
2057
  }>;
1866
2058
  }, z.core.$strict>>;
1867
2059
  }, z.core.$strict>;
1868
2060
  type WithheldKind = z.infer<typeof WithheldKind>;
2061
+ /**
2062
+ * One grant, named by both halves — V1-3.
2063
+ *
2064
+ * A job id is chosen per site, so the lease id is the unique thing an upstream
2065
+ * and a daemon can both point at. Anywhere a request says "this piece of work,
2066
+ * held by me", it says it with both.
2067
+ *
2068
+ * Declared once because it was written out twice — `activeLeases` and
2069
+ * `ReleaseRequest.leases` — and both needed the same `.strict()` added. Two
2070
+ * copies of a shape are two places to forget it.
2071
+ */
2072
+ declare const GrantRef: z.ZodObject<{
2073
+ jobId: z.ZodString;
2074
+ leaseId: z.ZodString;
2075
+ }, z.core.$strict>;
2076
+ type GrantRef = z.infer<typeof GrantRef>;
1869
2077
  /**
1870
2078
  * Pairing is a device-code exchange, not a pasted secret
1871
2079
  * ({@link MUSTS.PAIR_INTERACTIVE}). The daemon starts a pairing, shows the
@@ -1884,7 +2092,7 @@ declare const PairStartRequest: z.ZodObject<{
1884
2092
  linux: "linux";
1885
2093
  win32: "win32";
1886
2094
  }>;
1887
- }, z.core.$strip>;
2095
+ }, z.core.$strict>;
1888
2096
  device: z.ZodObject<{
1889
2097
  identity: z.ZodString;
1890
2098
  encryption: z.ZodString;
@@ -1896,7 +2104,6 @@ declare const PairStartRequest: z.ZodObject<{
1896
2104
  "llm.chat": "llm.chat";
1897
2105
  }>;
1898
2106
  service: z.ZodString;
1899
- isDefault: z.ZodBoolean;
1900
2107
  backendId: z.ZodEnum<{
1901
2108
  ollama: "ollama";
1902
2109
  mlx: "mlx";
@@ -1926,7 +2133,6 @@ declare const PairStartRequest: z.ZodObject<{
1926
2133
  offerScope: z.ZodEnum<{
1927
2134
  private: "private";
1928
2135
  team: "team";
1929
- public: "public";
1930
2136
  }>;
1931
2137
  }, z.core.$strict>>;
1932
2138
  }, z.core.$strict>;
@@ -1975,7 +2181,7 @@ declare const PairRequest: z.ZodDiscriminatedUnion<[z.ZodObject<{
1975
2181
  linux: "linux";
1976
2182
  win32: "win32";
1977
2183
  }>;
1978
- }, z.core.$strip>;
2184
+ }, z.core.$strict>;
1979
2185
  device: z.ZodObject<{
1980
2186
  identity: z.ZodString;
1981
2187
  encryption: z.ZodString;
@@ -1987,7 +2193,6 @@ declare const PairRequest: z.ZodDiscriminatedUnion<[z.ZodObject<{
1987
2193
  "llm.chat": "llm.chat";
1988
2194
  }>;
1989
2195
  service: z.ZodString;
1990
- isDefault: z.ZodBoolean;
1991
2196
  backendId: z.ZodEnum<{
1992
2197
  ollama: "ollama";
1993
2198
  mlx: "mlx";
@@ -2017,7 +2222,6 @@ declare const PairRequest: z.ZodDiscriminatedUnion<[z.ZodObject<{
2017
2222
  offerScope: z.ZodEnum<{
2018
2223
  private: "private";
2019
2224
  team: "team";
2020
- public: "public";
2021
2225
  }>;
2022
2226
  }, z.core.$strict>>;
2023
2227
  }, z.core.$strict>, z.ZodObject<{
@@ -2035,7 +2239,6 @@ declare const ClaimRequest: z.ZodObject<{
2035
2239
  "llm.chat": "llm.chat";
2036
2240
  }>;
2037
2241
  service: z.ZodString;
2038
- isDefault: z.ZodBoolean;
2039
2242
  backendId: z.ZodEnum<{
2040
2243
  ollama: "ollama";
2041
2244
  mlx: "mlx";
@@ -2065,7 +2268,6 @@ declare const ClaimRequest: z.ZodObject<{
2065
2268
  offerScope: z.ZodEnum<{
2066
2269
  private: "private";
2067
2270
  team: "team";
2068
- public: "public";
2069
2271
  }>;
2070
2272
  }, z.core.$strict>>;
2071
2273
  max: z.ZodNumber;
@@ -2083,9 +2285,8 @@ declare const ClaimResponse: z.ZodObject<{
2083
2285
  audience: z.ZodEnum<{
2084
2286
  private: "private";
2085
2287
  team: "team";
2086
- public: "public";
2087
2288
  }>;
2088
- service: z.ZodOptional<z.ZodString>;
2289
+ purpose: z.ZodOptional<z.ZodString>;
2089
2290
  sizeClass: z.ZodEnum<{
2090
2291
  small: "small";
2091
2292
  medium: "medium";
@@ -2098,7 +2299,19 @@ declare const ClaimResponse: z.ZodObject<{
2098
2299
  id: z.ZodString;
2099
2300
  runnerId: z.ZodString;
2100
2301
  expiresAt: z.ZodNumber;
2101
- }, z.core.$strip>;
2302
+ }, z.core.$strict>;
2303
+ grant: z.ZodOptional<z.ZodObject<{
2304
+ grantId: z.ZodString;
2305
+ jobId: z.ZodString;
2306
+ site: z.ZodString;
2307
+ user: z.ZodString;
2308
+ owner: z.ZodString;
2309
+ purpose: z.ZodString;
2310
+ kind: z.ZodString;
2311
+ service: z.ZodString;
2312
+ issuedAt: z.ZodNumber;
2313
+ signature: z.ZodString;
2314
+ }, z.core.$strict>>;
2102
2315
  }, z.core.$strict>>;
2103
2316
  leaseMs: z.ZodNumber;
2104
2317
  }, z.core.$strict>;
@@ -2113,7 +2326,6 @@ declare const HeartbeatRequest: z.ZodObject<{
2113
2326
  "llm.chat": "llm.chat";
2114
2327
  }>;
2115
2328
  service: z.ZodString;
2116
- isDefault: z.ZodBoolean;
2117
2329
  backendId: z.ZodEnum<{
2118
2330
  ollama: "ollama";
2119
2331
  mlx: "mlx";
@@ -2143,7 +2355,6 @@ declare const HeartbeatRequest: z.ZodObject<{
2143
2355
  offerScope: z.ZodEnum<{
2144
2356
  private: "private";
2145
2357
  team: "team";
2146
- public: "public";
2147
2358
  }>;
2148
2359
  }, z.core.$strict>>;
2149
2360
  withheld: z.ZodDefault<z.ZodArray<z.ZodObject<{
@@ -2156,14 +2367,13 @@ declare const HeartbeatRequest: z.ZodObject<{
2156
2367
  offer: z.ZodEnum<{
2157
2368
  private: "private";
2158
2369
  team: "team";
2159
- public: "public";
2160
2370
  }>;
2161
2371
  }, z.core.$strict>>;
2162
2372
  }, z.core.$strict>>>;
2163
2373
  activeLeases: z.ZodArray<z.ZodObject<{
2164
2374
  jobId: z.ZodString;
2165
2375
  leaseId: z.ZodString;
2166
- }, z.core.$strip>>;
2376
+ }, z.core.$strict>>;
2167
2377
  paused: z.ZodBoolean;
2168
2378
  }, z.core.$strict>;
2169
2379
  type HeartbeatRequest = z.infer<typeof HeartbeatRequest>;
@@ -2194,12 +2404,6 @@ declare const HeartbeatResponse: z.ZodObject<{
2194
2404
  }, z.core.$strict>>;
2195
2405
  serverTime: z.ZodNumber;
2196
2406
  awaitingConsent: z.ZodArray<z.ZodString>;
2197
- roster: z.ZodOptional<z.ZodObject<{
2198
- owner: z.ZodString;
2199
- members: z.ZodArray<z.ZodString>;
2200
- issuedAt: z.ZodNumber;
2201
- signature: z.ZodString;
2202
- }, z.core.$strict>>;
2203
2407
  }, z.core.$strict>;
2204
2408
  type HeartbeatResponse = z.infer<typeof HeartbeatResponse>;
2205
2409
  /**
@@ -2254,7 +2458,7 @@ declare const ReleaseRequest: z.ZodObject<{
2254
2458
  leases: z.ZodArray<z.ZodObject<{
2255
2459
  jobId: z.ZodString;
2256
2460
  leaseId: z.ZodString;
2257
- }, z.core.$strip>>;
2461
+ }, z.core.$strict>>;
2258
2462
  reason: z.ZodEnum<{
2259
2463
  refused: "refused";
2260
2464
  shutdown: "shutdown";
@@ -2335,4 +2539,4 @@ declare const FetchResponse: z.ZodObject<{
2335
2539
  }, z.core.$strict>;
2336
2540
  type FetchResponse = z.infer<typeof FetchResponse>;
2337
2541
 
2338
- export { AUDIENCES, Audience, BACKENDS, BACKEND_IDS, BackendClass, BackendCost, type BackendDescriptor, type BackendId, BackendIdSchema, Capability, CapabilityMatrix, ChatMessage, ChatPayload, ClaimRequest, ClaimResponse, ClaimedJob, ClaimedStub, DeliveredResult, ENCRYPTION_KEY_CONTEXT, ENDPOINTS, ENVELOPE_MAX_AGE_MS, ERROR_STATUS, type Endpoint, type EnvelopeContext, EnvelopeDirection, type EnvelopeFailure, FetchRequest, FetchResponse, GeneratePayload, HeartbeatRequest, HeartbeatResponse, JOB_KINDS, JobKind, JobOutcome, JobPayload, JobRefused, JobResultCanceled, JobResultError, JobResultOk, JobState, JobStub, KindedPayload, Lease, MAX_CLOCK_SKEW_MS, MAX_SUCCESSION_CHAIN, MIN_PROTOCOL_VERSION, MUSTS, MUST_IDS, type MatchDaemon, type MatchJob, MatchRefusal, type MatchResult, type Must, type MustEnforcer, type MustId, type MustVerification, type MustVerifiedBy, OFFER_SCOPES, OfferScope, type OpenResult, PAYLOAD_LIMITS, PROTOCOL_PREFIX, PROTOCOL_VERSION, PairPollRequest, PairPollResponse, PairRequest, PairStartRequest, PairStartResponse, type PayloadFor, PublicIdentity, REFUSAL_MESSAGES, RETIREMENT_WINDOW_MS, ROSTER_CONTEXT, ROSTER_MAX_AGE_MS, RefusalReason, ReleaseRequest, ReleaseResponse, RequestSignature, ResultDisposition, ResultProvenance, ResultRequest, ResultResponse, type RosterRefusal, RunMetadata, SIZE_CLASS_LIMITS, SUCCESSION_CONTEXT, SUPPORTED_PROTOCOL_VERSIONS, SealedEnvelope, SealedOutcome, type SignatureFailure, SignedRoster, SizeClass, type SpendConsent, StoredKeys, Succession, type SuccessionFailure, type SuccessionWalk, TERMINAL_STATES, type VersionRefusal, WireError, WireErrorCode, WithheldKind, backendDescriptor, backendName, canTransition, canonicalRequest, checkProtocolVersion, classifyCost, cryptoReady, declaredVersion, effectiveOfferScope, fingerprint, generateKeys, isBackendId, isCloudTaggedModel, isJobKind, isLocalHost, isTerminal, keyId, kindsOf, matchAudience, mustsVerifiedBy, open, payloadTextLength, provenanceFor, publicIdentityOf, resolveCost, rosterStatement, seal, signRequest, signRoster, signSiteRequest, signSuccession, signWith, sizeClassCeiling, sizeClassOf, successionStatement, verifyLink, verifyPublicIdentity, verifyRequest, verifyRoster, verifySiteRequest, verifyWith, walkSuccession };
2542
+ export { AUDIENCES, Audience, BACKENDS, BACKEND_IDS, BackendClass, BackendCost, type BackendDescriptor, type BackendId, BackendIdSchema, CLOCK_ATTRIBUTION_MS, CLOCK_SKEW_WARN_MS, Capability, CapabilityMatrix, ChatMessage, ChatPayload, ClaimRequest, ClaimResponse, ClaimedJob, ClaimedStub, DeliveredResult, ENCRYPTION_KEY_CONTEXT, ENDPOINTS, ENVELOPE_MAX_AGE_MS, ERROR_STATUS, type Endpoint, type EnvelopeContext, EnvelopeDirection, type EnvelopeFailure, FetchRequest, FetchResponse, GRANT_CONTEXT, GRANT_MAX_AGE_MS, GRANT_SIGNED_FIELDS, GeneratePayload, type GrantClaims, GrantRef, type GrantRefusal, HeartbeatRequest, HeartbeatResponse, JOB_KINDS, JobKind, JobOutcome, JobPayload, JobRefused, JobResultCanceled, JobResultError, JobResultOk, JobState, JobStub, KindedPayload, Lease, MAX_CLOCK_SKEW_MS, MAX_SUCCESSION_CHAIN, MIN_PROTOCOL_VERSION, MUSTS, MUST_IDS, Manifest, type MatchDaemon, type MatchJob, MatchRefusal, type MatchResult, type Must, type MustEnforcer, type MustId, type MustVerification, type MustVerifiedBy, OFFER_SCOPES, OfferScope, type OpenResult, PAYLOAD_LIMITS, PROTOCOL_PREFIX, PROTOCOL_VERSION, PairPollRequest, PairPollResponse, PairRequest, PairStartRequest, PairStartResponse, type PayloadFor, PublicIdentity, Purpose, REFUSAL_MESSAGES, RESERVED_PURPOSE, RETIREMENT_WINDOW_MS, RefusalReason, ReleaseRequest, ReleaseResponse, RequestSignature, ResultDisposition, ResultProvenance, ResultRequest, ResultResponse, RunMetadata, SIZE_CLASS_LIMITS, SUCCESSION_CONTEXT, SUPPORTED_PROTOCOL_VERSIONS, SealedEnvelope, SealedOutcome, type SignatureFailure, SignedGrant, SizeClass, type SpendConsent, StoredKeys, Succession, type SuccessionFailure, type SuccessionWalk, TERMINAL_STATES, type VersionRefusal, WireError, WireErrorCode, WithheldKind, backendDescriptor, backendName, canTransition, canonicalRequest, checkProtocolVersion, classifyCost, cryptoReady, declaredVersion, effectiveOfferScope, fingerprint, generateKeys, grantStatement, isBackendId, isCloudTaggedModel, isJobKind, isLocalHost, isTerminal, keyId, kindsOf, matchAudience, mustsVerifiedBy, open, payloadTextLength, provenanceFor, publicIdentityOf, resolveCost, seal, signGrant, signRequest, signSiteRequest, signSuccession, signWith, singlePurposeManifest, sizeClassCeiling, sizeClassOf, successionStatement, verifyGrant, verifyLink, verifyPublicIdentity, verifyRequest, verifySiteRequest, verifyWith, walkSuccession };