@agentshouse/mdruntime 0.1.0-alpha.3 → 0.1.0-alpha.4

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.
@@ -2,9 +2,11 @@ import { query as evaluate } from '@agentshouse/query';
2
2
  import { ROOM_CONTRACT_VERSION, VERSION_1_CAPABILITIES } from './adapter.js';
3
3
  import { bootstrapRoom } from './bootstrap.js';
4
4
  import { MD_MODEL, PRESENTED } from './collection.js';
5
+ import { createLog } from './log.js';
6
+ import { queuedOutcome, refused } from './outcome.js';
5
7
  import { refreshRoom } from './refresh.js';
6
8
  import { buildBatch } from './save.js';
7
- import { readConfirmed, replicaOf } from './replica.js';
9
+ import { applyReturned, readConfirmed, replicaOf } from './replica.js';
8
10
  import { settled, same, saving, STARTING, transferring } from './status.js';
9
11
  import { openReplicaStore } from './store.js';
10
12
  import { unconfirmed } from './transfer.js';
@@ -17,7 +19,9 @@ export function createMdRuntime(options) {
17
19
  let store;
18
20
  const replicas = new Map();
19
21
  const drafts = new Map();
22
+ const outcomes = new Map();
20
23
  let limits = [];
24
+ let capabilities = [];
21
25
  const rooms = new Map();
22
26
  const unreadable = new Set();
23
27
  let refusal = null;
@@ -34,6 +38,11 @@ export function createMdRuntime(options) {
34
38
  const statusListeners = new Set();
35
39
  const querySubscriptions = new Set();
36
40
  const queueSubscriptions = new Set();
41
+ const journal = createLog();
42
+ let notifyReady = ()=>{};
43
+ const ready = new Promise((resolve)=>{
44
+ notifyReady = resolve;
45
+ });
37
46
  function at(locator, path) {
38
47
  return `${locator} ${path}`;
39
48
  }
@@ -42,6 +51,29 @@ export function createMdRuntime(options) {
42
51
  ...replicas.values()
43
52
  ].some((replica)=>replica.queue.length > 0);
44
53
  }
54
+ function attention() {
55
+ return [
56
+ ...replicas.values()
57
+ ].some((replica)=>{
58
+ const head = replica.queue[0];
59
+ return head !== undefined && refused(outcomes.get(head.id));
60
+ });
61
+ }
62
+ function storedOutcomes(batches) {
63
+ const stored = {};
64
+ for (const batch of batches){
65
+ const outcome = queuedOutcome(outcomes.get(batch.id));
66
+ if (outcome.kind !== 'pending') stored[batch.id] = outcome;
67
+ }
68
+ return stored;
69
+ }
70
+ async function persistQueue(local, locator, batches) {
71
+ await local.writeQueue({
72
+ locator,
73
+ batches,
74
+ outcomes: storedOutcomes(batches)
75
+ });
76
+ }
45
77
  function listed() {
46
78
  return [
47
79
  ...rooms.values()
@@ -84,13 +116,18 @@ export function createMdRuntime(options) {
84
116
  subscription.notify(visible(subscription.query));
85
117
  }
86
118
  }
87
- function queueOf(locator) {
88
- return replicas.get(locator)?.queue ?? [];
119
+ function entriesOf(locator) {
120
+ const replica = replicas.get(locator);
121
+ if (replica === undefined) return [];
122
+ return replica.queue.map((batch)=>Object.freeze({
123
+ batch,
124
+ outcome: queuedOutcome(outcomes.get(batch.id))
125
+ }));
89
126
  }
90
127
  function emitQueue(locator) {
91
- const batches = queueOf(locator);
128
+ const entries = entriesOf(locator);
92
129
  for (const subscription of queueSubscriptions){
93
- if (subscription.locator === locator) subscription.notify(batches);
130
+ if (subscription.locator === locator) subscription.notify(entries);
94
131
  }
95
132
  }
96
133
  function stopTimer() {
@@ -111,6 +148,7 @@ export function createMdRuntime(options) {
111
148
  reason,
112
149
  reauthorizationOffered: reason === 'revoked-authorization'
113
150
  };
151
+ journal.record(`connection refused ${reason}`);
114
152
  emitRefusal();
115
153
  }
116
154
  function list(room, synchronizationAvailable) {
@@ -154,6 +192,11 @@ export function createMdRuntime(options) {
154
192
  queue.locator,
155
193
  queue.batches
156
194
  ]));
195
+ for (const queue of queues){
196
+ for (const [id, outcome] of Object.entries(queue.outcomes)){
197
+ outcomes.set(id, outcome);
198
+ }
199
+ }
157
200
  for (const record of records){
158
201
  const confirmed = readConfirmed(record);
159
202
  if (confirmed === null) continue;
@@ -162,7 +205,8 @@ export function createMdRuntime(options) {
162
205
  }
163
206
  moveTo({
164
207
  ...status,
165
- lastCompleted
208
+ lastCompleted,
209
+ attentionRequired: attention()
166
210
  });
167
211
  if (replicas.size > 0) {
168
212
  emitRooms();
@@ -192,7 +236,7 @@ export function createMdRuntime(options) {
192
236
  emitVisible();
193
237
  });
194
238
  }
195
- async function write(locator, changes) {
239
+ async function write(locator, changes, replacing) {
196
240
  const replica = replicas.get(locator);
197
241
  const room = rooms.get(locator);
198
242
  if (replica === undefined || room === undefined) {
@@ -210,32 +254,183 @@ export function createMdRuntime(options) {
210
254
  outcome: 'refused',
211
255
  ...built.refusal
212
256
  };
257
+ const head = replica.queue[0];
258
+ if (replacing !== undefined) {
259
+ if (head === undefined || head.id !== replacing || !refused(outcomes.get(head.id))) {
260
+ return {
261
+ outcome: 'refused',
262
+ rule: 'no-refused-head'
263
+ };
264
+ }
265
+ }
213
266
  const local = await openLocal();
214
- const batches = [
267
+ const batches = replacing === undefined ? [
215
268
  ...replica.queue,
216
269
  built.batch
270
+ ] : [
271
+ built.batch,
272
+ ...replica.queue.slice(1)
217
273
  ];
274
+ if (replacing !== undefined) outcomes.delete(replacing);
218
275
  const consumed = [
219
276
  ...new Set(changes.map((change)=>change.path))
220
277
  ];
221
278
  await local.append({
222
279
  locator,
223
- batches
280
+ batches,
281
+ outcomes: storedOutcomes(batches)
224
282
  }, consumed);
225
283
  for (const path of consumed)drafts.delete(at(locator, path));
226
284
  replicas.set(locator, replicaOf(replica.confirmed, batches));
227
285
  emitQueue(locator);
228
286
  emitVisible();
229
- moveTo(saving(status));
287
+ moveTo({
288
+ ...saving(status),
289
+ attentionRequired: attention()
290
+ });
291
+ void enqueue();
230
292
  return {
231
293
  outcome: 'saved',
232
294
  id: built.batch.id
233
295
  };
234
296
  }
297
+ async function discardHead(locator, identifier) {
298
+ const replica = replicas.get(locator);
299
+ const head = replica?.queue[0];
300
+ if (replica === undefined || head === undefined || head.id !== identifier || !refused(outcomes.get(head.id))) {
301
+ return;
302
+ }
303
+ const local = await openLocal();
304
+ const batches = replica.queue.slice(1);
305
+ outcomes.delete(identifier);
306
+ await persistQueue(local, locator, batches);
307
+ replicas.set(locator, replicaOf(replica.confirmed, batches));
308
+ emitQueue(locator);
309
+ emitVisible();
310
+ moveTo({
311
+ ...status,
312
+ state: pending() ? 'pending' : status.state,
313
+ attentionRequired: attention()
314
+ });
315
+ void enqueue();
316
+ }
317
+ async function readHistory(locator, path, query = {}) {
318
+ if (closed || refusal !== null) return {
319
+ kind: 'transport-uncertainty'
320
+ };
321
+ try {
322
+ await ensureAuthorization();
323
+ } catch {
324
+ return {
325
+ kind: 'transport-uncertainty'
326
+ };
327
+ }
328
+ if (closed || authorization === undefined || refusal !== null) {
329
+ return {
330
+ kind: 'transport-uncertainty'
331
+ };
332
+ }
333
+ const transfer = [
334
+ 'transfer',
335
+ 'history',
336
+ locator,
337
+ path
338
+ ];
339
+ if (query.revision !== undefined) transfer.push(query.revision);
340
+ if (query.pageToken !== undefined) transfer.push(query.pageToken);
341
+ journal.record(transfer.join(' '));
342
+ try {
343
+ const result = await options.adapter.history(authorization, {
344
+ locator,
345
+ path,
346
+ ...query.revision === undefined ? {} : {
347
+ revision: query.revision
348
+ },
349
+ ...query.pageToken === undefined ? {} : {
350
+ pageToken: query.pageToken
351
+ }
352
+ });
353
+ journal.record(`outcome history ${result.kind}`);
354
+ if (result.kind === 'revoked-authorization') refuse('revoked-authorization');
355
+ return result;
356
+ } catch {
357
+ journal.record('outcome history transport-uncertainty');
358
+ return {
359
+ kind: 'transport-uncertainty'
360
+ };
361
+ }
362
+ }
363
+ function declaredAction(name) {
364
+ for (const capability of capabilities){
365
+ for (const action of capability.actions ?? []){
366
+ if (action.name === name) return action;
367
+ }
368
+ }
369
+ return undefined;
370
+ }
371
+ async function invokeAction(name, input) {
372
+ await ready;
373
+ if (closed || refusal !== null) return {
374
+ kind: 'transport-uncertainty'
375
+ };
376
+ if (declaredAction(name) === undefined) return {
377
+ kind: 'undeclared'
378
+ };
379
+ try {
380
+ await ensureAuthorization();
381
+ } catch {
382
+ return {
383
+ kind: 'transport-uncertainty'
384
+ };
385
+ }
386
+ if (closed || authorization === undefined || refusal !== null) {
387
+ return {
388
+ kind: 'transport-uncertainty'
389
+ };
390
+ }
391
+ journal.record(`transfer action ${name}`);
392
+ try {
393
+ const result = await options.adapter.action(authorization, {
394
+ name,
395
+ input
396
+ });
397
+ if (result.kind === 'revoked-authorization') refuse('revoked-authorization');
398
+ journal.record(`outcome action ${result.kind}`);
399
+ if (result.kind === 'rejected') journal.record(`refusal rejected ${result.text}`);
400
+ return result;
401
+ } catch {
402
+ journal.record('outcome action transport-uncertainty');
403
+ return {
404
+ kind: 'transport-uncertainty'
405
+ };
406
+ }
407
+ }
408
+ async function pullRefresh(authorized, confirmed) {
409
+ try {
410
+ const result = await refreshRoom(options.adapter, authorized, confirmed);
411
+ const detail = result.kind === 'advanced' ? result.confirmed.record.roomVersion : result.kind;
412
+ journal.record(`transfer refresh ${confirmed.record.locator} ${detail}`);
413
+ return result;
414
+ } catch (error) {
415
+ journal.record(`transfer refresh ${confirmed.record.locator} transport-uncertainty`);
416
+ throw error;
417
+ }
418
+ }
419
+ async function pullBootstrap(authorized, room) {
420
+ try {
421
+ const result = await bootstrapRoom(options.adapter, authorized, room);
422
+ const detail = result.kind === 'staged' ? result.confirmed.record.roomVersion : result.kind;
423
+ journal.record(`transfer bootstrap ${room.locator} ${detail}`);
424
+ return result;
425
+ } catch (error) {
426
+ journal.record(`transfer bootstrap ${room.locator} transport-uncertainty`);
427
+ throw error;
428
+ }
429
+ }
235
430
  async function advance(room, local, authorized) {
236
431
  const held = replicas.get(room.locator);
237
432
  if (held !== undefined) {
238
- const refreshed = await refreshRoom(options.adapter, authorized, held.confirmed);
433
+ const refreshed = await pullRefresh(authorized, held.confirmed);
239
434
  if (refreshed.kind === 'still-current') {
240
435
  if (unreadable.delete(room.locator)) {
241
436
  list(room, true);
@@ -250,62 +445,242 @@ export function createMdRuntime(options) {
250
445
  }
251
446
  if (refreshed.kind !== 'beyond-horizon') return refreshed;
252
447
  }
253
- const bootstrapped = await bootstrapRoom(options.adapter, authorized, room);
448
+ const bootstrapped = await pullBootstrap(authorized, room);
254
449
  if (bootstrapped.kind !== 'staged') return bootstrapped;
255
450
  if (closed) return unconfirmed;
256
451
  await publish(local, room, bootstrapped.confirmed);
257
452
  return null;
258
453
  }
259
- async function synchronize(discovered, local, progress) {
260
- for (const room of discovered){
261
- if (closed || authorization === undefined) {
454
+ function recordRefusal(result) {
455
+ if (result.kind === 'expired') return {
456
+ kind: 'expired'
457
+ };
458
+ if (result.kind === 'conflicted') {
459
+ return {
460
+ kind: 'conflicted',
461
+ roomVersion: result.roomVersion,
462
+ affected: result.affected,
463
+ text: result.text
464
+ };
465
+ }
466
+ return {
467
+ kind: 'rejected',
468
+ affected: result.affected,
469
+ text: result.text
470
+ };
471
+ }
472
+ async function commitAccept(room, local, submitted, accepted, base, overlay) {
473
+ const current = replicas.get(room.locator);
474
+ if (current === undefined || !current.queue.some((batch)=>batch.id === submitted.id)) {
475
+ return true;
476
+ }
477
+ const remaining = current.queue.filter((batch)=>batch.id !== submitted.id);
478
+ const applied = overlay ? applyReturned(base, accepted.documents, accepted.revisions, accepted.removals, accepted.roomVersion) : base;
479
+ if (applied === null) return false;
480
+ await local.publish(applied.record);
481
+ await persistQueue(local, room.locator, remaining);
482
+ outcomes.set(submitted.id, {
483
+ kind: 'accepted',
484
+ roomVersion: accepted.roomVersion,
485
+ author: accepted.author,
486
+ time: accepted.time
487
+ });
488
+ unreadable.delete(room.locator);
489
+ replicas.set(room.locator, replicaOf(applied, remaining));
490
+ list(room, true);
491
+ emitRooms();
492
+ emitQueue(room.locator);
493
+ emitVisible();
494
+ journal.record(`outcome ${room.locator} ${submitted.id} accepted`);
495
+ return true;
496
+ }
497
+ async function submitRoom(room, local, authorized, progress) {
498
+ while(!closed && authorization !== undefined){
499
+ const replica = replicas.get(room.locator);
500
+ const head = replica?.queue[0];
501
+ if (replica === undefined || head === undefined || refused(outcomes.get(head.id))) {
502
+ return null;
503
+ }
504
+ let result;
505
+ journal.record(`submission ${room.locator} ${head.id}`);
506
+ try {
507
+ result = await options.adapter.mutate(authorized, {
508
+ locator: room.locator,
509
+ changeBatch: head
510
+ });
511
+ } catch {
262
512
  progress.complete = false;
263
- return;
513
+ progress.reachable = false;
514
+ return null;
264
515
  }
265
- const withheld = await advance(room, local, authorization);
266
- if (withheld === null) continue;
267
- progress.complete = false;
268
- if (withheld.kind === 'transport-uncertainty') {
516
+ if (closed) return null;
517
+ if (result.kind === 'transport-uncertainty') {
518
+ progress.complete = false;
269
519
  progress.reachable = false;
270
- continue;
520
+ return null;
271
521
  }
272
- if (withheld.kind === 'room-not-readable') {
522
+ if (result.kind === 'room-not-readable') {
523
+ progress.complete = false;
273
524
  unreadable.add(room.locator);
274
525
  list(room, false);
275
526
  emitRooms();
276
- continue;
527
+ return null;
277
528
  }
278
- if (withheld.kind === 'revoked-authorization') {
529
+ if (result.kind === 'revoked-authorization') {
279
530
  refuse('revoked-authorization');
531
+ return 'stop';
532
+ }
533
+ if (result.kind === 'conflicted' || result.kind === 'rejected' || result.kind === 'expired') {
534
+ journal.record(`outcome ${room.locator} ${head.id} ${result.kind}`);
535
+ if (result.kind !== 'expired') journal.record(`refusal ${result.kind} ${result.text}`);
536
+ await exclusive(async ()=>{
537
+ const current = replicas.get(room.locator);
538
+ if (current === undefined || !current.queue.some((batch)=>batch.id === head.id)) {
539
+ return;
540
+ }
541
+ outcomes.set(head.id, recordRefusal(result));
542
+ await persistQueue(local, room.locator, current.queue);
543
+ emitQueue(room.locator);
544
+ moveTo({
545
+ ...status,
546
+ attentionRequired: true
547
+ });
548
+ });
549
+ return null;
550
+ }
551
+ const from = replicas.get(room.locator)?.confirmed;
552
+ if (from === undefined) return null;
553
+ const pulled = await pullRefresh(authorized, from);
554
+ if (pulled.kind === 'revoked-authorization') {
555
+ refuse('revoked-authorization');
556
+ return 'stop';
557
+ }
558
+ if (pulled.kind === 'still-current') {
559
+ const committed = await exclusive(()=>commitAccept(room, local, head, result, from, true));
560
+ if (!committed) {
561
+ progress.complete = false;
562
+ return null;
563
+ }
564
+ continue;
565
+ }
566
+ if (pulled.kind === 'advanced') {
567
+ const overlay = pulled.confirmed.record.roomVersion === result.roomVersion;
568
+ const committed = await exclusive(()=>commitAccept(room, local, head, result, pulled.confirmed, overlay));
569
+ if (!committed) {
570
+ progress.complete = false;
571
+ return null;
572
+ }
573
+ continue;
574
+ }
575
+ if (pulled.kind === 'beyond-horizon') {
576
+ const bootstrapped = await pullBootstrap(authorized, room);
577
+ if (bootstrapped.kind === 'revoked-authorization') {
578
+ refuse('revoked-authorization');
579
+ return 'stop';
580
+ }
581
+ if (bootstrapped.kind === 'staged') {
582
+ const overlay = bootstrapped.confirmed.record.roomVersion === result.roomVersion;
583
+ const committed = await exclusive(()=>commitAccept(room, local, head, result, bootstrapped.confirmed, overlay));
584
+ if (!committed) {
585
+ progress.complete = false;
586
+ return null;
587
+ }
588
+ continue;
589
+ }
590
+ progress.complete = false;
591
+ if (bootstrapped.kind === 'transport-uncertainty') {
592
+ progress.reachable = false;
593
+ } else if (bootstrapped.kind === 'room-not-readable') {
594
+ unreadable.add(room.locator);
595
+ list(room, false);
596
+ emitRooms();
597
+ }
598
+ return null;
599
+ }
600
+ progress.complete = false;
601
+ if (pulled.kind === 'transport-uncertainty') {
602
+ progress.reachable = false;
603
+ } else if (pulled.kind === 'room-not-readable') {
604
+ unreadable.add(room.locator);
605
+ list(room, false);
606
+ emitRooms();
607
+ }
608
+ return null;
609
+ }
610
+ return null;
611
+ }
612
+ async function synchronize(discovered, local, progress) {
613
+ for (const room of discovered){
614
+ if (closed || authorization === undefined) {
615
+ progress.complete = false;
280
616
  return;
281
617
  }
618
+ const withheld = await advance(room, local, authorization);
619
+ if (withheld !== null) {
620
+ progress.complete = false;
621
+ if (withheld.kind === 'transport-uncertainty') {
622
+ progress.reachable = false;
623
+ continue;
624
+ }
625
+ if (withheld.kind === 'room-not-readable') {
626
+ unreadable.add(room.locator);
627
+ list(room, false);
628
+ emitRooms();
629
+ continue;
630
+ }
631
+ if (withheld.kind === 'revoked-authorization') {
632
+ refuse('revoked-authorization');
633
+ return;
634
+ }
635
+ continue;
636
+ }
637
+ if (await submitRoom(room, local, authorization, progress) === 'stop') return;
282
638
  }
283
639
  }
284
640
  async function cycle(local, progress) {
285
- if (closed || authorization === undefined) return;
641
+ if (closed || authorization === undefined) {
642
+ notifyReady();
643
+ return;
644
+ }
286
645
  moveTo(transferring(status));
287
- const result = await options.adapter.discover(authorization);
288
- if (closed) return;
646
+ let result;
647
+ try {
648
+ result = await options.adapter.discover(authorization);
649
+ } catch (error) {
650
+ journal.record('connection discover transport-uncertainty');
651
+ notifyReady();
652
+ throw error;
653
+ }
654
+ if (closed) {
655
+ notifyReady();
656
+ return;
657
+ }
658
+ journal.record(`connection discover ${result.kind}`);
289
659
  if (result.kind === 'transport-uncertainty') {
290
660
  progress.reachable = false;
661
+ notifyReady();
291
662
  return;
292
663
  }
293
664
  if (result.kind === 'revoked-authorization') {
294
665
  refuse('revoked-authorization');
666
+ notifyReady();
295
667
  return;
296
668
  }
297
669
  if (!result.supportedVersions.includes(ROOM_CONTRACT_VERSION)) {
298
670
  refuse('no-matching-version');
671
+ notifyReady();
299
672
  return;
300
673
  }
301
674
  if (result.mdModel.identity !== MD_MODEL.identity || result.mdModel.version !== MD_MODEL.version) {
302
675
  refuse('md-model-version-mismatch');
676
+ notifyReady();
303
677
  return;
304
678
  }
305
679
  const declared = new Set(result.capabilities.map((capability)=>capability.name));
306
680
  for (const required of options.requiredGuarantees){
307
681
  if (!knownCapabilities.has(required) || !declared.has(required)) {
308
682
  refuse('missing-required-guarantee');
683
+ notifyReady();
309
684
  return;
310
685
  }
311
686
  }
@@ -313,6 +688,8 @@ export function createMdRuntime(options) {
313
688
  refusal = null;
314
689
  emitRefusal();
315
690
  }
691
+ capabilities = result.capabilities;
692
+ notifyReady();
316
693
  if (JSON.stringify(result.providerLimits) !== JSON.stringify(limits)) {
317
694
  limits = result.providerLimits;
318
695
  await local.declare(limits);
@@ -325,10 +702,19 @@ export function createMdRuntime(options) {
325
702
  }
326
703
  async function ensureAuthorization() {
327
704
  if (authorization !== undefined) return;
328
- authorization = await options.adapter.authorize();
705
+ try {
706
+ authorization = await options.adapter.authorize();
707
+ journal.record('connection authorize');
708
+ } catch (error) {
709
+ journal.record('connection authorize transport-uncertainty');
710
+ throw error;
711
+ }
329
712
  }
330
713
  async function connect() {
331
- if (closed || discoveryPaused) return;
714
+ if (closed || discoveryPaused) {
715
+ notifyReady();
716
+ return;
717
+ }
332
718
  startTimer();
333
719
  const progress = {
334
720
  complete: false,
@@ -348,9 +734,11 @@ export function createMdRuntime(options) {
348
734
  }
349
735
  } catch {
350
736
  progress.complete = false;
737
+ notifyReady();
351
738
  return;
352
739
  } finally{
353
- moveTo(settled(status, progress, completedAt, pending()));
740
+ notifyReady();
741
+ moveTo(settled(status, progress, completedAt, pending(), attention()));
354
742
  }
355
743
  }
356
744
  async function run() {
@@ -420,8 +808,32 @@ export function createMdRuntime(options) {
420
808
  drafts.delete(at(locator, path));
421
809
  }
422
810
  },
423
- save (locator, changes) {
424
- return exclusive(()=>write(locator, changes));
811
+ save (locator, changes, replacing) {
812
+ return exclusive(()=>write(locator, changes, replacing));
813
+ },
814
+ outcome (identifier) {
815
+ const recorded = outcomes.get(identifier);
816
+ if (recorded !== undefined) return recorded;
817
+ for (const replica of replicas.values()){
818
+ if (replica.queue.some((batch)=>batch.id === identifier)) return {
819
+ kind: 'pending'
820
+ };
821
+ }
822
+ return null;
823
+ },
824
+ queue: {
825
+ discard (locator, identifier) {
826
+ return exclusive(()=>discardHead(locator, identifier));
827
+ }
828
+ },
829
+ history (locator, path, query) {
830
+ return readHistory(locator, path, query);
831
+ },
832
+ call (name, input) {
833
+ return invokeAction(name, input);
834
+ },
835
+ log () {
836
+ return journal.export();
425
837
  },
426
838
  observe (topic, second, third) {
427
839
  if (topic === 'rooms') {
@@ -454,7 +866,7 @@ export function createMdRuntime(options) {
454
866
  notify: third
455
867
  };
456
868
  queueSubscriptions.add(queue);
457
- queue.notify(queueOf(queue.locator));
869
+ queue.notify(entriesOf(queue.locator));
458
870
  return ()=>{
459
871
  queueSubscriptions.delete(queue);
460
872
  };
@@ -472,6 +884,7 @@ export function createMdRuntime(options) {
472
884
  },
473
885
  async reauthorize () {
474
886
  if (refusal === null || !refusal.reauthorizationOffered) return;
887
+ journal.record('connection reauthorize');
475
888
  authorization = undefined;
476
889
  discoveryPaused = false;
477
890
  await enqueue();