@byollm/protocol 0.1.0-alpha.44 → 0.1.0-alpha.46

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/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  > [!WARNING]
2
- > **Alpha (`0.1.0-alpha.44`) — under active development. Don't use this yet.**
2
+ > **Alpha (`0.1.0-alpha.46`) — under active development. Don't use this yet.**
3
3
  >
4
4
  > Install it deliberately: `npm install @byollm/protocol@alpha`.
5
5
  >
@@ -83,7 +83,7 @@
83
83
  > packages published and `@byollm/server` did not: a Sigstore
84
84
  > transparency-log 409 on its provenance attestation. The workflow's
85
85
  > "already published" guard correctly refuses to resume a partial publish,
86
- > so `0.1.0-alpha.44` is that release, whole.
86
+ > so `0.1.0-alpha.46` is that release, whole.
87
87
  >
88
88
  > If you run the Supabase adapter, `alpha.21` needs
89
89
  > `20260819010000_completed_by_lease_id.sql`: alpha.19 shipped §3.6's
package/dist/index.d.ts CHANGED
@@ -659,6 +659,58 @@ declare const JobOutcome: z.ZodDiscriminatedUnion<[z.ZodObject<{
659
659
  outcome: z.ZodLiteral<"canceled">;
660
660
  }, z.core.$strict>], "outcome">;
661
661
  type JobOutcome = z.infer<typeof JobOutcome>;
662
+ /**
663
+ * Why a job can never run — byollm_016 Phase B.
664
+ *
665
+ * Every one of these is **terminal**, and that is the whole point of naming
666
+ * them. A job that cannot be matched used to sit queued until its deadline,
667
+ * which reads exactly like a job that is merely waiting for a device to come
668
+ * online — so an app could not tell "any moment now" from "never", and neither
669
+ * could the person watching a spinner. Silence must never read as pending.
670
+ *
671
+ * They are decided by whoever knows first: the site's own SDK where it can see
672
+ * the answer without asking, the router where matching happens, and the daemon
673
+ * again on arrival under the both-sides rule. All three reason from the same
674
+ * list rather than three private vocabularies.
675
+ */
676
+ declare const RefusalReason: z.ZodEnum<{
677
+ "select-unavailable": "select-unavailable";
678
+ "default-ambiguity": "default-ambiguity";
679
+ "default-unusable": "default-unusable";
680
+ }>;
681
+ type RefusalReason = z.infer<typeof RefusalReason>;
682
+ /**
683
+ * A terminal outcome nobody sealed — byollm_016 Phase B.
684
+ *
685
+ * Every other finished job carries an envelope encrypted by the device that
686
+ * ran it, which is what makes a result unforgeable. These have no device: the
687
+ * job was refused *before* anything could run it, so there is nobody to seal
688
+ * from and no content to seal.
689
+ *
690
+ * **What that costs, stated plainly.** This is the one terminal outcome a
691
+ * router can author. It is worth being exact about the power that grants,
692
+ * because "the relay can write this" sounds alarming until you compare it with
693
+ * what a relay could already do: drop the job, never offer it, and let it
694
+ * expire. A router-authored refusal is *denial of service by a shorter route*,
695
+ * which is a power the router has always had and which the trust model has
696
+ * always said it has. What it emphatically is **not** is forgery: this shape
697
+ * carries no envelope and no output, so it can never be mistaken for an answer
698
+ * a device produced. A relay still cannot fabricate a result, because that
699
+ * needs a signature it does not hold.
700
+ *
701
+ * So the rule this shape enforces by construction: a refusal may deny, and may
702
+ * never assert. Anything that claims work was *done* still comes sealed.
703
+ */
704
+ declare const JobRefused: z.ZodObject<{
705
+ outcome: z.ZodLiteral<"refused">;
706
+ reason: z.ZodEnum<{
707
+ "select-unavailable": "select-unavailable";
708
+ "default-ambiguity": "default-ambiguity";
709
+ "default-unusable": "default-unusable";
710
+ }>;
711
+ message: z.ZodString;
712
+ }, z.core.$strict>;
713
+ type JobRefused = z.infer<typeof JobRefused>;
662
714
  /**
663
715
  * The plaintext inside a result envelope.
664
716
  *
@@ -799,6 +851,7 @@ declare const JobStub: z.ZodObject<{
799
851
  team: "team";
800
852
  public: "public";
801
853
  }>;
854
+ service: z.ZodOptional<z.ZodString>;
802
855
  sizeClass: z.ZodEnum<{
803
856
  small: "small";
804
857
  medium: "medium";
@@ -823,6 +876,7 @@ declare const ClaimedStub: z.ZodObject<{
823
876
  team: "team";
824
877
  public: "public";
825
878
  }>;
879
+ service: z.ZodOptional<z.ZodString>;
826
880
  sizeClass: z.ZodEnum<{
827
881
  small: "small";
828
882
  medium: "medium";
@@ -1398,6 +1452,27 @@ declare const MUSTS: Readonly<{
1398
1452
  readonly PROVENANCE_NAMES_DEVICE: Must;
1399
1453
  readonly INGRESS_LOGGED_BEFORE_EXECUTION: Must;
1400
1454
  readonly NO_SHELL_INTERPOLATION: Must;
1455
+ /**
1456
+ * Amended for byollm_016 Phase B, and the amendment is deliberately narrow.
1457
+ *
1458
+ * A site may now name a **service** on the stub. The temptation is to read
1459
+ * that as a crack in this law, so the statement below says exactly where the
1460
+ * line is: a name selects from a menu the owner published, and resolves to a
1461
+ * model, backend, base URL and flags **only** through that owner's own
1462
+ * config. The site supplies a key; the owner supplies every value it maps
1463
+ * to. A name the owner does not advertise is refused rather than
1464
+ * substituted, because substitution is how "you may pick from my list" turns
1465
+ * into "you may ask for anything and get something".
1466
+ *
1467
+ * Two properties keep it from drifting into "sites demand models":
1468
+ *
1469
+ * 1. **Nothing the site sends is ever a value.** No model string, no URL,
1470
+ * no flag crosses the wire — only a key that means nothing off this
1471
+ * owner's machine.
1472
+ * 2. **It is a stub field, never a payload field.** The prompt cannot
1473
+ * reach it. That is unchanged and is the sentence the second clause
1474
+ * below still enforces verbatim.
1475
+ */
1401
1476
  readonly NO_PAYLOAD_ROUTING: Must;
1402
1477
  readonly STRIPPED_CHILD_ENV: Must;
1403
1478
  readonly HTTP_BASE_URL_SAFE: Must;
@@ -1823,6 +1898,7 @@ declare const ClaimResponse: z.ZodObject<{
1823
1898
  team: "team";
1824
1899
  public: "public";
1825
1900
  }>;
1901
+ service: z.ZodOptional<z.ZodString>;
1826
1902
  sizeClass: z.ZodEnum<{
1827
1903
  small: "small";
1828
1904
  medium: "medium";
@@ -1986,11 +2062,11 @@ declare const ReleaseRequest: z.ZodObject<{
1986
2062
  leaseId: z.ZodString;
1987
2063
  }, z.core.$strip>>;
1988
2064
  reason: z.ZodEnum<{
2065
+ refused: "refused";
1989
2066
  shutdown: "shutdown";
1990
2067
  pause: "pause";
1991
2068
  revoked: "revoked";
1992
2069
  "backend-down": "backend-down";
1993
- refused: "refused";
1994
2070
  }>;
1995
2071
  }, z.core.$strict>;
1996
2072
  type ReleaseRequest = z.infer<typeof ReleaseRequest>;
@@ -2065,4 +2141,4 @@ declare const FetchResponse: z.ZodObject<{
2065
2141
  }, z.core.$strict>;
2066
2142
  type FetchResponse = z.infer<typeof FetchResponse>;
2067
2143
 
2068
- 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, 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, ReleaseRequest, ReleaseResponse, RequestSignature, ResultDisposition, ResultProvenance, ResultRequest, ResultResponse, RunMetadata, SIZE_CLASS_LIMITS, SUCCESSION_CONTEXT, SUPPORTED_PROTOCOL_VERSIONS, SealedEnvelope, SealedOutcome, type SignatureFailure, SizeClass, type SpendConsent, StoredKeys, Succession, type SuccessionFailure, type SuccessionWalk, TERMINAL_STATES, type VersionRefusal, WireError, WireErrorCode, WithheldKind, backendDescriptor, canTransition, canonicalRequest, checkProtocolVersion, cryptoReady, declaredVersion, effectiveOfferScope, fingerprint, generateKeys, isBackendId, isCloudTaggedModel, isJobKind, isLocalHost, isTerminal, keyId, kindsOf, matchAudience, mustsVerifiedBy, open, payloadTextLength, provenanceFor, publicIdentityOf, resolveCost, seal, signRequest, signSiteRequest, signSuccession, signWith, sizeClassCeiling, sizeClassOf, successionStatement, verifyLink, verifyPublicIdentity, verifyRequest, verifySiteRequest, verifyWith, walkSuccession };
2144
+ 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, RefusalReason, ReleaseRequest, ReleaseResponse, RequestSignature, ResultDisposition, ResultProvenance, ResultRequest, ResultResponse, RunMetadata, SIZE_CLASS_LIMITS, SUCCESSION_CONTEXT, SUPPORTED_PROTOCOL_VERSIONS, SealedEnvelope, SealedOutcome, type SignatureFailure, SizeClass, type SpendConsent, StoredKeys, Succession, type SuccessionFailure, type SuccessionWalk, TERMINAL_STATES, type VersionRefusal, WireError, WireErrorCode, WithheldKind, backendDescriptor, canTransition, canonicalRequest, checkProtocolVersion, cryptoReady, declaredVersion, effectiveOfferScope, fingerprint, generateKeys, isBackendId, isCloudTaggedModel, isJobKind, isLocalHost, isTerminal, keyId, kindsOf, matchAudience, mustsVerifiedBy, open, payloadTextLength, provenanceFor, publicIdentityOf, resolveCost, seal, signRequest, signSiteRequest, signSuccession, signWith, sizeClassCeiling, sizeClassOf, successionStatement, verifyLink, verifyPublicIdentity, verifyRequest, verifySiteRequest, verifyWith, walkSuccession };
package/dist/index.js CHANGED
@@ -466,6 +466,67 @@ var JobOutcome = z4.discriminatedUnion("outcome", [
466
466
  JobResultError,
467
467
  JobResultCanceled
468
468
  ]);
469
+ var RefusalReason = z4.enum([
470
+ /**
471
+ * A selection this requester cannot be served — byollm_016 Phase B.
472
+ *
473
+ * **One value for two causes, and the collapse is the security property.**
474
+ * A named service may be unknown to this owner, or known and not offered to
475
+ * this requester. Those are different facts and the requester may learn
476
+ * neither, because telling them apart turns refusal wording into an
477
+ * inventory oracle: probe names, sort the answers, and enumerate a device
478
+ * you were never offered. The finer cause lives owner-side, where the person
479
+ * reading it already owns the machine — see {@link SelectionFailure}.
480
+ *
481
+ * The first draft of this enum had both causes on the wire with a comment
482
+ * claiming they disclosed identically. They did not; the comment described a
483
+ * property the code lacked, which is the more dangerous half of that mistake.
484
+ */
485
+ "select-unavailable",
486
+ /**
487
+ * Two or more services answer this kind and the owner has named no default,
488
+ * so the kind is withheld. Nobody may pick on the owner's behalf — the wrong
489
+ * guess is the metered one.
490
+ *
491
+ * Not collapsed into the value above, and the reason is that a kind is not
492
+ * probeable. There are two kinds; a requester asking about one is not
493
+ * enumerating a namespace, and learns nothing they could not learn by
494
+ * looking at what the device advertises. It is also already what a roster
495
+ * member sees on the devices page — `awaitingDefault` carries exactly this,
496
+ * by kind, for exactly this reason.
497
+ */
498
+ "default-ambiguity",
499
+ /**
500
+ * A default exists and this requester can never use it — byollm_016's
501
+ * defaults-meet-audiences corner.
502
+ *
503
+ * The specimen: an owner's default for `llm.chat` is their Claude
504
+ * subscription, self-locked by `SUBSCRIPTION_SELF_LOCK`. A team member's
505
+ * unselected job resolves to it and can never be served by it. That must be
506
+ * a refusal on the spot, not a wait that expires an hour later looking like
507
+ * nobody was online.
508
+ *
509
+ * Bounded like the value above and probeable for the same reason it is not:
510
+ * the requester named nothing, so there is no name space to walk.
511
+ */
512
+ "default-unusable"
513
+ ]);
514
+ var JobRefused = z4.object({
515
+ outcome: z4.literal("refused"),
516
+ reason: RefusalReason,
517
+ /** Plain words for a human reading a log, never parsed. */
518
+ message: z4.string().min(1)
519
+ }).strict();
520
+ var REFUSAL_TEXT = Object.freeze({
521
+ "select-unavailable": "that service is not available to you on this device",
522
+ "default-ambiguity": "this device serves that kind from more than one service and its owner has not chosen which",
523
+ "default-unusable": "this device's default for that kind cannot run work for you"
524
+ });
525
+ var REFUSED_SELECTION = Object.freeze({
526
+ outcome: "refused",
527
+ reason: "select-unavailable",
528
+ message: REFUSAL_TEXT["select-unavailable"]
529
+ });
469
530
  var SealedOutcome = z4.object({ outcome: JobOutcome, ran: RunMetadata }).strict();
470
531
  var DeliveredResult = z4.object({
471
532
  jobId: z4.string().min(1),
@@ -553,6 +614,30 @@ var JobStub = z4.object({
553
614
  // The site keeps its own copy on `JobRecord` and still filters candidates
554
615
  // with it before offering. That is server-internal, where the party
555
616
  // holding the list authored it.
617
+ /**
618
+ * Which of the owner's services should answer — byollm_016 Phase B.
619
+ *
620
+ * **A selection from a menu, never a demand.** The owner advertises named
621
+ * services; a site may name one of them, and that is the entire power the
622
+ * field grants. It carries no model, no base URL, no flags — the daemon
623
+ * resolves the name against its own config and nothing else, so what
624
+ * actually runs is still decided exclusively by the person who owns the
625
+ * hardware. A name that is not on that owner's menu is refused
626
+ * (`select-unadvertised`), never silently substituted, because a
627
+ * substitution is how "select" would quietly become "whatever we had".
628
+ *
629
+ * Absent means "the owner's default for this kind", which is the only
630
+ * behaviour Phase A had.
631
+ *
632
+ * It travels because the router matches on it, under the rule the absent
633
+ * `audienceAllow` above establishes: *a class the router acts on may
634
+ * travel; membership never does.* This is a class.
635
+ *
636
+ * It is a **stub** field and never a payload field, which is the line
637
+ * `NO_PAYLOAD_ROUTING` draws: the prompt cannot reach it, so no amount of
638
+ * user text can influence what runs.
639
+ */
640
+ service: z4.string().min(1).optional(),
556
641
  sizeClass: SizeClass,
557
642
  /** Reserved for byollm_006. False until streaming exists. */
558
643
  streaming: z4.boolean(),
@@ -1221,12 +1306,33 @@ var MUSTS = Object.freeze({
1221
1306
  verifiedBy: "adversarial",
1222
1307
  source: "byollm_004 \xA72"
1223
1308
  }),
1309
+ /**
1310
+ * Amended for byollm_016 Phase B, and the amendment is deliberately narrow.
1311
+ *
1312
+ * A site may now name a **service** on the stub. The temptation is to read
1313
+ * that as a crack in this law, so the statement below says exactly where the
1314
+ * line is: a name selects from a menu the owner published, and resolves to a
1315
+ * model, backend, base URL and flags **only** through that owner's own
1316
+ * config. The site supplies a key; the owner supplies every value it maps
1317
+ * to. A name the owner does not advertise is refused rather than
1318
+ * substituted, because substitution is how "you may pick from my list" turns
1319
+ * into "you may ask for anything and get something".
1320
+ *
1321
+ * Two properties keep it from drifting into "sites demand models":
1322
+ *
1323
+ * 1. **Nothing the site sends is ever a value.** No model string, no URL,
1324
+ * no flag crosses the wire — only a key that means nothing off this
1325
+ * owner's machine.
1326
+ * 2. **It is a stub field, never a payload field.** The prompt cannot
1327
+ * reach it. That is unchanged and is the sentence the second clause
1328
+ * below still enforces verbatim.
1329
+ */
1224
1330
  NO_PAYLOAD_ROUTING: must({
1225
1331
  id: "NO_PAYLOAD_ROUTING",
1226
- statement: "Model, backend, base URL, and flags MUST come from owner config only; a payload MUST NOT influence any of them.",
1332
+ statement: "Model, backend, base URL, and flags MUST come from owner config only; a payload MUST NOT influence any of them. A stub MAY name a service the owner advertises, which selects among that owner's own config entries and MUST NOT introduce any value the owner did not write; an unadvertised name MUST be refused, never substituted.",
1227
1333
  enforcedBy: "daemon",
1228
1334
  verifiedBy: "adversarial",
1229
- source: "byollm_004 \xA72"
1335
+ source: "byollm_004 \xA72, amended byollm_016 \xA7Phase B"
1230
1336
  }),
1231
1337
  STRIPPED_CHILD_ENV: must({
1232
1338
  id: "STRIPPED_CHILD_ENV",
@@ -1967,6 +2073,7 @@ export {
1967
2073
  JobKind,
1968
2074
  JobOutcome,
1969
2075
  JobPayload,
2076
+ JobRefused,
1970
2077
  JobResultCanceled,
1971
2078
  JobResultError,
1972
2079
  JobResultOk,
@@ -1993,6 +2100,7 @@ export {
1993
2100
  PublicIdentity,
1994
2101
  REFUSAL_MESSAGES,
1995
2102
  RETIREMENT_WINDOW_MS,
2103
+ RefusalReason,
1996
2104
  ReleaseRequest,
1997
2105
  ReleaseResponse,
1998
2106
  RequestSignature,