@byollm/relay 0.1.0-alpha.9 → 0.1.0-alpha.90

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.
@@ -0,0 +1,642 @@
1
+ import {
2
+ routeKey
3
+ } from "./chunk-TOLKQRTU.js";
4
+
5
+ // src/store-contract.ts
6
+ import { generateKeys, publicIdentityOf } from "@byollm/protocol";
7
+ import { describe, expect, it } from "vitest";
8
+ var CONTRACT_SITE = "site_store";
9
+ var SITE_KEY_ID = "BYOLLM-TEST-SITE-KEY-ID";
10
+ var SITE = CONTRACT_SITE;
11
+ var stub = (id, owner = "alice") => ({
12
+ id,
13
+ kind: "llm.generate",
14
+ owner,
15
+ site: SITE_KEY_ID,
16
+ audience: "private",
17
+ sizeClass: "small",
18
+ streaming: false,
19
+ deadlineAt: 41024448e5
20
+ });
21
+ var capability = (model) => ({
22
+ kind: "llm.generate",
23
+ service: model,
24
+ backendId: "ollama",
25
+ backendClass: "process",
26
+ model,
27
+ offerScope: "private"
28
+ });
29
+ var ENVELOPE = {
30
+ ciphertext: "AAAA",
31
+ recipientKeyId: "r",
32
+ senderKeyId: "s",
33
+ direction: "payload",
34
+ deadlineAt: 41024448e5
35
+ };
36
+ var claimArgs = (over = {}) => {
37
+ const { owners = ["alice"], sites = [SITE], ...rest } = over;
38
+ return {
39
+ runnerId: "runner_1",
40
+ owner: "alice",
41
+ device: publicIdentityOf(generateKeys(Date.now())),
42
+ kinds: /* @__PURE__ */ new Set(["llm.generate"]),
43
+ routes: new Set(
44
+ sites.flatMap((site) => owners.map((owner) => routeKey(site, owner)))
45
+ ),
46
+ max: 10,
47
+ leaseMs: 6e4,
48
+ ...rest
49
+ };
50
+ };
51
+ function describeStoreContract(name, options) {
52
+ const { make, serialising, writeRawStub } = options;
53
+ describe(`the routing store \u2014 ${name}`, () => {
54
+ it("is idempotent by job id", async () => {
55
+ const { store, done } = await make();
56
+ await store.enqueue({ id: "a", siteId: SITE, stub: stub("a") });
57
+ await store.claim(claimArgs());
58
+ await store.enqueue({ id: "a", siteId: SITE, stub: stub("a") });
59
+ expect((await store.job(SITE, "a"))?.state).toBe("awaiting-payload");
60
+ await done();
61
+ });
62
+ it("gives two sites the same id without either seeing the other", async () => {
63
+ const { store, done } = await make();
64
+ await store.enqueue({ id: "shared", siteId: SITE, stub: stub("shared") });
65
+ await store.enqueue({
66
+ id: "shared",
67
+ siteId: "site_other",
68
+ stub: stub("shared", "bob")
69
+ });
70
+ expect((await store.job(SITE, "shared"))?.stub.owner).toBe("alice");
71
+ expect((await store.job("site_other", "shared"))?.stub.owner).toBe("bob");
72
+ const granted = await store.claim(claimArgs());
73
+ expect(granted.map((job) => job.id)).toEqual(["shared"]);
74
+ expect(granted[0]?.owner).toBe("alice");
75
+ const replay = await store.enqueue({
76
+ id: "shared",
77
+ siteId: SITE,
78
+ stub: stub("shared")
79
+ });
80
+ expect(replay).toEqual(await store.job(SITE, "shared"));
81
+ await done();
82
+ });
83
+ it("grants only what the owners set allows", async () => {
84
+ const { store, done } = await make();
85
+ await store.enqueue({ id: "mine", siteId: SITE, stub: stub("mine") });
86
+ await store.enqueue({
87
+ id: "theirs",
88
+ siteId: SITE,
89
+ stub: stub("theirs", "mallory")
90
+ });
91
+ const granted = await store.claim(claimArgs());
92
+ expect(granted.map((job) => job.id)).toEqual(["mine"]);
93
+ await done();
94
+ });
95
+ it("refuses a stale lease and honours the current one", async () => {
96
+ const { store, done } = await make();
97
+ await store.enqueue({ id: "a", siteId: SITE, stub: stub("a") });
98
+ const [granted] = await store.claim(claimArgs());
99
+ await store.seal({ jobId: "a", siteId: SITE, envelope: ENVELOPE });
100
+ expect(
101
+ await store.takePayload({
102
+ jobId: "a",
103
+ runnerId: "runner_1",
104
+ leaseId: "an-older-grant"
105
+ })
106
+ ).toEqual({ refused: "stale-lease" });
107
+ expect(
108
+ await store.takePayload({
109
+ jobId: "a",
110
+ runnerId: "runner_1",
111
+ leaseId: granted.lease.id
112
+ })
113
+ ).toEqual({ envelope: ENVELOPE });
114
+ await done();
115
+ });
116
+ it("will not answer for one job with another job's lease", async () => {
117
+ const { store, done } = await make();
118
+ await store.enqueue({ id: "mine", siteId: SITE, stub: stub("mine") });
119
+ await store.enqueue({ id: "other", siteId: SITE, stub: stub("other") });
120
+ const granted = await store.claim(claimArgs());
121
+ const mine = granted.find((job) => job.id === "mine");
122
+ const other = granted.find((job) => job.id === "other");
123
+ await store.seal({ jobId: "other", siteId: SITE, envelope: ENVELOPE });
124
+ expect(
125
+ await store.takePayload({
126
+ jobId: "other",
127
+ runnerId: "runner_1",
128
+ leaseId: mine.lease.id
129
+ })
130
+ ).toEqual({ refused: "stale-lease" });
131
+ expect(
132
+ await store.takePayload({
133
+ jobId: "other",
134
+ runnerId: "runner_1",
135
+ leaseId: other.lease.id
136
+ })
137
+ ).toEqual({ envelope: ENVELOPE });
138
+ await done();
139
+ });
140
+ it("renews a grant it still holds, and extends the sweep with it", async () => {
141
+ const { store, done } = await make();
142
+ await store.enqueue({ id: "a", siteId: SITE, stub: stub("a") });
143
+ const [granted] = await store.claim(claimArgs({ leaseMs: 1e3 }));
144
+ const renewed = await store.renewLeases({
145
+ runnerId: "runner_1",
146
+ leases: [{ jobId: "a", leaseId: granted.lease.id }],
147
+ leaseMs: 6e4
148
+ });
149
+ expect(renewed.lost).toEqual([]);
150
+ expect(renewed.renewed.map((r) => r.jobId)).toEqual(["a"]);
151
+ expect(renewed.renewed[0].expiresAt).toBeGreaterThan(
152
+ granted.lease.expiresAt
153
+ );
154
+ expect((await store.job(SITE, "a"))?.claimedBy?.leaseExpiresAt).toBe(
155
+ renewed.renewed[0].expiresAt
156
+ );
157
+ await done();
158
+ });
159
+ it("reports a lease the runner no longer holds as lost, and renews nothing", async () => {
160
+ const { store, done } = await make();
161
+ await store.enqueue({ id: "a", siteId: SITE, stub: stub("a") });
162
+ const [granted] = await store.claim(claimArgs({ leaseMs: 1e3 }));
163
+ const before = (await store.job(SITE, "a"))?.claimedBy?.leaseExpiresAt;
164
+ const renewed = await store.renewLeases({
165
+ runnerId: "runner_1",
166
+ leases: [{ jobId: "a", leaseId: "a-grant-that-ended" }],
167
+ leaseMs: 6e4
168
+ });
169
+ expect(renewed.renewed).toEqual([]);
170
+ expect(renewed.lost).toEqual([
171
+ { jobId: "a", leaseId: "a-grant-that-ended" }
172
+ ]);
173
+ expect((await store.job(SITE, "a"))?.claimedBy?.leaseExpiresAt).toBe(
174
+ before
175
+ );
176
+ expect((await store.job(SITE, "a"))?.claimedBy?.leaseId).toBe(
177
+ granted.lease.id
178
+ );
179
+ await done();
180
+ });
181
+ it("does not hand out a stub it cannot parse", async () => {
182
+ const { store, done } = await make();
183
+ if (!serialising || writeRawStub === void 0) {
184
+ await done();
185
+ return;
186
+ }
187
+ await store.enqueue({ id: "good", siteId: SITE, stub: stub("good") });
188
+ await store.enqueue({ id: "old", siteId: SITE, stub: stub("old") });
189
+ const legacy = { ...stub("old") };
190
+ delete legacy["site"];
191
+ await writeRawStub(store, "old", JSON.stringify(legacy));
192
+ const granted = await store.claim(claimArgs({ max: 10 }));
193
+ expect(granted.map((job) => job.id)).toEqual(["good"]);
194
+ expect((await store.job(SITE, "old"))?.state).toBe("queued");
195
+ await done();
196
+ });
197
+ it("honours a self job's audience", async () => {
198
+ const { store, done } = await make();
199
+ await store.enqueue({
200
+ id: "private",
201
+ siteId: SITE,
202
+ stub: { ...stub("private", "alice"), audience: "private" }
203
+ });
204
+ const granted = await store.claim(
205
+ claimArgs({ owner: "owner", owners: ["owner", "alice"] })
206
+ );
207
+ expect(granted).toEqual([]);
208
+ expect((await store.job(SITE, "private"))?.state).toBe("queued");
209
+ await done();
210
+ });
211
+ it("still offers that job to its owner's own machine", async () => {
212
+ const { store, done } = await make();
213
+ await store.enqueue({
214
+ id: "private",
215
+ siteId: SITE,
216
+ stub: { ...stub("private", "alice"), audience: "private" }
217
+ });
218
+ const granted = await store.claim(
219
+ claimArgs({ owner: "alice", owners: ["alice"] })
220
+ );
221
+ expect(granted.map((job) => job.id)).toEqual(["private"]);
222
+ await done();
223
+ });
224
+ it("does not offer a job back to the runner that refused it", async () => {
225
+ const { store, done } = await make();
226
+ await store.enqueue({ id: "a", siteId: SITE, stub: stub("a") });
227
+ const [granted] = await store.claim(claimArgs());
228
+ await store.releaseLeases({
229
+ runnerId: "runner_1",
230
+ leases: [{ jobId: "a", leaseId: granted.lease.id }],
231
+ reason: "refused"
232
+ });
233
+ expect(await store.claim(claimArgs())).toEqual([]);
234
+ expect((await store.job(SITE, "a"))?.state).toBe("queued");
235
+ expect(
236
+ (await store.claim(claimArgs({ runnerId: "runner_2" }))).map(
237
+ (j) => j.id
238
+ )
239
+ ).toEqual(["a"]);
240
+ await done();
241
+ });
242
+ it("does not offer a job back to a runner before its not-before", async () => {
243
+ const { store, done } = await make();
244
+ await store.enqueue({ id: "a", siteId: SITE, stub: stub("a") });
245
+ const [granted] = await store.claim(claimArgs());
246
+ await store.releaseLeases({
247
+ runnerId: "runner_1",
248
+ leases: [{ jobId: "a", leaseId: granted.lease.id }],
249
+ retryAfter: Date.now() + 6e5
250
+ });
251
+ expect(await store.claim(claimArgs())).toEqual([]);
252
+ expect((await store.job(SITE, "a"))?.state).toBe("queued");
253
+ expect(
254
+ (await store.claim(claimArgs({ runnerId: "runner_2" }))).map(
255
+ (j) => j.id
256
+ )
257
+ ).toEqual(["a"]);
258
+ await done();
259
+ });
260
+ it("offers it again once the not-before has passed", async () => {
261
+ const { store, done } = await make();
262
+ await store.enqueue({ id: "a", siteId: SITE, stub: stub("a") });
263
+ const [granted] = await store.claim(claimArgs());
264
+ await store.releaseLeases({
265
+ runnerId: "runner_1",
266
+ leases: [{ jobId: "a", leaseId: granted.lease.id }],
267
+ retryAfter: Date.now() - 1e3
268
+ });
269
+ expect((await store.claim(claimArgs())).map((j) => j.id)).toEqual(["a"]);
270
+ await done();
271
+ });
272
+ it("will not un-finish a job that is already done", async () => {
273
+ const { store, done } = await make();
274
+ await store.enqueue({ id: "a", siteId: SITE, stub: stub("a") });
275
+ const [granted] = await store.claim(claimArgs());
276
+ const lease = granted.lease.id;
277
+ await store.takePayload({
278
+ jobId: "a",
279
+ runnerId: "runner_1",
280
+ leaseId: lease
281
+ });
282
+ await store.complete({
283
+ jobId: "a",
284
+ runnerId: "runner_1",
285
+ leaseId: lease,
286
+ envelope: ENVELOPE,
287
+ disposition: "ok"
288
+ });
289
+ const released = await store.releaseLeases({
290
+ runnerId: "runner_1",
291
+ leases: [{ jobId: "a", leaseId: lease }],
292
+ reason: "shutdown"
293
+ });
294
+ expect(released).toEqual([]);
295
+ expect((await store.job(SITE, "a"))?.state).toBe("done");
296
+ expect((await store.finished(SITE)).map((j) => j.id)).toEqual(["a"]);
297
+ expect(await store.claim(claimArgs({ runnerId: "runner_2" }))).toEqual(
298
+ []
299
+ );
300
+ await done();
301
+ });
302
+ it("keeps a job claimable by a runner that only went away", async () => {
303
+ const { store, done } = await make();
304
+ await store.enqueue({ id: "a", siteId: SITE, stub: stub("a") });
305
+ const [granted] = await store.claim(claimArgs());
306
+ await store.releaseLeases({
307
+ runnerId: "runner_1",
308
+ leases: [{ jobId: "a", leaseId: granted.lease.id }],
309
+ reason: "shutdown"
310
+ });
311
+ expect((await store.claim(claimArgs())).map((j) => j.id)).toEqual(["a"]);
312
+ await done();
313
+ });
314
+ it("stops offering a job past its deadline, and drops the ciphertext", async () => {
315
+ const { store, done } = await make();
316
+ await store.enqueue({
317
+ id: "late",
318
+ siteId: SITE,
319
+ stub: { ...stub("late"), deadlineAt: Date.now() - 1e3 }
320
+ });
321
+ expect(await store.claim(claimArgs())).toEqual([]);
322
+ expect(await store.job(SITE, "late")).toBeUndefined();
323
+ await done();
324
+ });
325
+ it("reports what a sweep removed, not only what it requeued \u2014 B096", async () => {
326
+ const { store, done } = await make();
327
+ await store.enqueue({
328
+ id: "expired",
329
+ siteId: SITE,
330
+ stub: { ...stub("expired"), deadlineAt: Date.now() - 1e3 }
331
+ });
332
+ await store.enqueue({ id: "alive", siteId: SITE, stub: stub("alive") });
333
+ const swept = await store.sweep();
334
+ expect(
335
+ swept.map((job) => job.id),
336
+ "a sweep removed a job and reported nothing about it"
337
+ ).toContain("expired");
338
+ expect(swept.map((job) => job.id)).not.toContain("alive");
339
+ expect(await store.job(SITE, "alive")).toBeDefined();
340
+ await done();
341
+ });
342
+ it("names a cancelled job to the device holding it, and offers it to nobody", async () => {
343
+ const { store, done } = await make();
344
+ await store.enqueue({ id: "a", siteId: SITE, stub: stub("a") });
345
+ await store.claim(claimArgs());
346
+ expect(await store.cancel({ jobId: "a", siteId: SITE })).toBe(true);
347
+ const held = (await store.job(SITE, "a"))?.claimedBy?.leaseId;
348
+ expect(await store.cancelRequests("runner_1")).toEqual([
349
+ { jobId: "a", leaseId: held }
350
+ ]);
351
+ expect(await store.cancel({ jobId: "a", siteId: "someone_else" })).toBe(
352
+ false
353
+ );
354
+ await done();
355
+ });
356
+ it("records a result once", async () => {
357
+ const { store, done } = await make();
358
+ await store.enqueue({ id: "a", siteId: SITE, stub: stub("a") });
359
+ const [granted] = await store.claim(claimArgs());
360
+ const first = await store.complete({
361
+ jobId: "a",
362
+ runnerId: "runner_1",
363
+ leaseId: granted.lease.id,
364
+ envelope: ENVELOPE,
365
+ disposition: "ok"
366
+ });
367
+ const replay = await store.complete({
368
+ jobId: "a",
369
+ runnerId: "runner_1",
370
+ leaseId: granted.lease.id,
371
+ envelope: { ...ENVELOPE, ciphertext: "different" },
372
+ disposition: "error"
373
+ });
374
+ expect(first).toEqual({ accepted: true, state: "done" });
375
+ expect(replay).toEqual({
376
+ accepted: false,
377
+ duplicate: true,
378
+ state: "done"
379
+ });
380
+ expect((await store.job(SITE, "a"))?.disposition).toBe("ok");
381
+ await done();
382
+ });
383
+ it("answers the device that finished it with `duplicate`", async () => {
384
+ const { store, done } = await make();
385
+ await store.enqueue({ id: "a", siteId: SITE, stub: stub("a") });
386
+ const [granted] = await store.claim(claimArgs());
387
+ const first = await store.complete({
388
+ jobId: "a",
389
+ runnerId: "runner_1",
390
+ leaseId: granted.lease.id,
391
+ envelope: ENVELOPE,
392
+ disposition: "ok"
393
+ });
394
+ expect(first).toEqual({ accepted: true, state: "done" });
395
+ const replay = await store.complete({
396
+ jobId: "a",
397
+ runnerId: "runner_1",
398
+ leaseId: granted.lease.id,
399
+ envelope: { ...ENVELOPE, ciphertext: "a-different-result" },
400
+ disposition: "error"
401
+ });
402
+ expect(replay).toEqual({
403
+ accepted: false,
404
+ duplicate: true,
405
+ state: "done"
406
+ });
407
+ const stranger = await store.complete({
408
+ jobId: "a",
409
+ runnerId: "runner_2",
410
+ leaseId: granted.lease.id,
411
+ envelope: ENVELOPE,
412
+ disposition: "ok"
413
+ });
414
+ expect(stranger).toEqual({ refused: "not-holder" });
415
+ expect((await store.job(SITE, "a"))?.disposition).toBe("ok");
416
+ await done();
417
+ });
418
+ it("refuses a result produced under a grant that ended", async () => {
419
+ const { store, done } = await make();
420
+ await store.enqueue({ id: "a", siteId: SITE, stub: stub("a") });
421
+ await store.claim(claimArgs());
422
+ const late = await store.complete({
423
+ jobId: "a",
424
+ runnerId: "runner_1",
425
+ leaseId: "a-grant-that-ended",
426
+ envelope: ENVELOPE,
427
+ disposition: "ok"
428
+ });
429
+ expect(late).toEqual({ refused: "stale-lease" });
430
+ expect((await store.job(SITE, "a"))?.state).toBe("awaiting-payload");
431
+ expect((await store.job(SITE, "a"))?.result).toBeUndefined();
432
+ await done();
433
+ });
434
+ it("refuses a payload for a job that already finished [V1-6]", async () => {
435
+ const { store, done } = await make();
436
+ await store.enqueue({ id: "a", siteId: SITE, stub: stub("a") });
437
+ const [granted] = await store.claim(claimArgs());
438
+ await store.seal({ jobId: "a", siteId: SITE, envelope: ENVELOPE });
439
+ await store.takePayload({
440
+ jobId: "a",
441
+ runnerId: "runner_1",
442
+ leaseId: granted.lease.id
443
+ });
444
+ await store.complete({
445
+ jobId: "a",
446
+ runnerId: "runner_1",
447
+ leaseId: granted.lease.id,
448
+ envelope: ENVELOPE,
449
+ disposition: "ok"
450
+ });
451
+ const replay = await store.takePayload({
452
+ jobId: "a",
453
+ runnerId: "runner_1",
454
+ leaseId: granted.lease.id
455
+ });
456
+ expect(replay).toEqual({ refused: "terminal" });
457
+ expect((await store.job(SITE, "a"))?.state).toBe("done");
458
+ await done();
459
+ });
460
+ it("tells a runner nothing about another site's job id [V1-8]", async () => {
461
+ const { store, done } = await make();
462
+ await store.enqueue({
463
+ id: "secret",
464
+ siteId: "site_somebody_else",
465
+ stub: stub("secret")
466
+ });
467
+ await store.enqueue({ id: "mine", siteId: SITE, stub: stub("mine") });
468
+ const granted = await store.claim(claimArgs());
469
+ const mine = granted.find((job) => job.id === "mine");
470
+ const other = await store.takePayload({
471
+ jobId: "secret",
472
+ runnerId: "runner_1",
473
+ leaseId: mine.lease.id
474
+ });
475
+ const absent = await store.takePayload({
476
+ jobId: "no-such-job-anywhere",
477
+ runnerId: "runner_1",
478
+ leaseId: mine.lease.id
479
+ });
480
+ expect(other).toEqual(absent);
481
+ expect(other).toEqual({ refused: "not-found" });
482
+ await done();
483
+ });
484
+ it("offers a job to any device that serves its kind", async () => {
485
+ const { store, done } = await make();
486
+ await store.enqueue({ id: "a", siteId: SITE, stub: stub("a") });
487
+ const claimed = await store.claim(
488
+ claimArgs({ runnerId: "runner_any", kinds: /* @__PURE__ */ new Set(["llm.generate"]) })
489
+ );
490
+ expect(claimed.map((j) => j.id)).toEqual(["a"]);
491
+ await done();
492
+ });
493
+ it("does not offer a job to a device that serves a different kind", async () => {
494
+ const { store, done } = await make();
495
+ await store.enqueue({ id: "a", siteId: SITE, stub: stub("a") });
496
+ const claimed = await store.claim(
497
+ claimArgs({ runnerId: "runner_chat", kinds: /* @__PURE__ */ new Set(["llm.chat"]) })
498
+ );
499
+ expect(claimed).toEqual([]);
500
+ await done();
501
+ });
502
+ it("remembers a device, and what it says it can run", async () => {
503
+ const { store, done } = await make();
504
+ const device = publicIdentityOf(generateKeys(3e12));
505
+ await store.seen({
506
+ runnerId: "runner_1",
507
+ owner: "alice",
508
+ device,
509
+ capabilities: [capability("llama3")],
510
+ withheld: []
511
+ });
512
+ const known = await store.presence("runner_1");
513
+ expect(known?.owner).toBe("alice");
514
+ expect(known?.device.identity).toBe(device.identity);
515
+ expect(known?.capabilities.map((row) => row.model)).toEqual(["llama3"]);
516
+ await done();
517
+ });
518
+ it("replaces the matrix rather than merging it", async () => {
519
+ const { store, done } = await make();
520
+ const device = publicIdentityOf(generateKeys(3000000000001));
521
+ const seen = { runnerId: "runner_2", owner: "alice", device };
522
+ await store.seen({
523
+ ...seen,
524
+ capabilities: [capability("llama3")],
525
+ withheld: []
526
+ });
527
+ await store.seen({
528
+ ...seen,
529
+ capabilities: [capability("mistral")],
530
+ withheld: []
531
+ });
532
+ const known = await store.presence("runner_2");
533
+ expect(known?.capabilities.map((row) => row.model)).toEqual(["mistral"]);
534
+ await done();
535
+ });
536
+ it("keeps an empty matrix, because empty is an answer", async () => {
537
+ const { store, done } = await make();
538
+ const device = publicIdentityOf(generateKeys(3000000000002));
539
+ const seen = { runnerId: "runner_3", owner: "alice", device };
540
+ await store.seen({
541
+ ...seen,
542
+ capabilities: [capability("llama3")],
543
+ withheld: []
544
+ });
545
+ await store.seen({ ...seen, capabilities: [], withheld: [] });
546
+ expect((await store.presence("runner_3"))?.capabilities).toEqual([]);
547
+ await done();
548
+ });
549
+ it("remembers which kinds are withheld, and drops them when resolved", async () => {
550
+ const { store, done } = await make();
551
+ const device = publicIdentityOf(generateKeys(3000000000004));
552
+ const seen = { runnerId: "runner_withheld", owner: "alice", device };
553
+ await store.seen({
554
+ ...seen,
555
+ capabilities: [],
556
+ withheld: [
557
+ {
558
+ kind: "llm.generate",
559
+ claimants: [
560
+ { service: "ollama", offer: "team" },
561
+ { service: "mlx", offer: "private" }
562
+ ]
563
+ }
564
+ ]
565
+ });
566
+ const held = await store.presence("runner_withheld");
567
+ expect(held?.withheld.map((row) => row.kind)).toEqual(["llm.generate"]);
568
+ expect(held?.withheld[0]?.claimants.map((c) => c.service)).toEqual([
569
+ "ollama",
570
+ "mlx"
571
+ ]);
572
+ await store.seen({
573
+ ...seen,
574
+ capabilities: [capability("llama3")],
575
+ withheld: []
576
+ });
577
+ expect((await store.presence("runner_withheld"))?.withheld).toEqual([]);
578
+ await done();
579
+ });
580
+ it("stamps presence from its own clock, and moves it on the next beat", async () => {
581
+ const { store, done } = await make();
582
+ const device = publicIdentityOf(generateKeys(3000000000003));
583
+ const seen = { runnerId: "runner_4", owner: "alice", device };
584
+ const before = await store.now();
585
+ const first = await store.seen({
586
+ ...seen,
587
+ capabilities: [],
588
+ withheld: []
589
+ });
590
+ expect(first.lastSeenAt).toBeGreaterThanOrEqual(before);
591
+ const later = await store.seen({
592
+ ...seen,
593
+ capabilities: [],
594
+ withheld: []
595
+ });
596
+ expect(later.lastSeenAt).toBeGreaterThanOrEqual(first.lastSeenAt);
597
+ await done();
598
+ });
599
+ it("lists everyone it has seen", async () => {
600
+ const { store, done } = await make();
601
+ await store.seen({
602
+ runnerId: "runner_5",
603
+ owner: "alice",
604
+ device: publicIdentityOf(generateKeys(3000000000004)),
605
+ capabilities: [],
606
+ withheld: []
607
+ });
608
+ await store.seen({
609
+ runnerId: "runner_6",
610
+ owner: "bob",
611
+ device: publicIdentityOf(generateKeys(3000000000005)),
612
+ capabilities: [],
613
+ withheld: []
614
+ });
615
+ const everyone = await store.everyone();
616
+ const ids = everyone.map((row) => row.runnerId);
617
+ expect(ids).toContain("runner_5");
618
+ expect(ids).toContain("runner_6");
619
+ await done();
620
+ });
621
+ it("does not know a runner it has never seen", async () => {
622
+ const { store, done } = await make();
623
+ expect(await store.presence("runner_never")).toBeUndefined();
624
+ await done();
625
+ });
626
+ it("stamps deadlines from its own clock", async () => {
627
+ const { store, done } = await make();
628
+ await store.enqueue({ id: "a", siteId: SITE, stub: stub("a") });
629
+ const before = await store.now();
630
+ const [granted] = await store.claim(claimArgs({ leaseMs: 45e3 }));
631
+ const after = await store.now();
632
+ expect(granted.lease.expiresAt).toBeGreaterThanOrEqual(before + 45e3);
633
+ expect(granted.lease.expiresAt).toBeLessThanOrEqual(after + 45e3);
634
+ await done();
635
+ });
636
+ });
637
+ }
638
+ export {
639
+ CONTRACT_SITE,
640
+ describeStoreContract
641
+ };
642
+ //# sourceMappingURL=store-contract.js.map