@githolon/runtime 0.119.31 → 0.119.33

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.
@@ -71,10 +71,10 @@
71
71
  33c06d52cd2978f920c683b281370b4622d8037bc4a2149c06d49ca40223e522 peer-office/src/runtime/records_desk.ts
72
72
  33e7d6bdd22396057d3f8db92384079f7ec2fda4b3582709de2d43fccacc4a9c node_modules/@bufbuild/protobuf/dist/esm/codegenv2/extension.js
73
73
  34700c9b62d55b63b0cac5659fc10d2869d77809e0137c74216b58d6d9736515 adapter/kernel_failure.ts
74
- 34a51508782f443beb3bca1c913363899979696b94ff480330363390570e7514 peer-office/src/runtime/live_correspondence_desk.ts
75
74
  34f8712de2bd30a2cb8366d8cfdcde466d979f1a28ac0d78f7547341b01f6c57 adapter/proto/nomos/kernel/v1/progress_pb.js
76
75
  37645d541d10a4f7782107f8d75449dd0b656b1a852e9e743919e216a1d314b0 peer-office/src/runtime/replica_follow_state.ts
77
76
  37f83564e2b43d3b488740b42eb4951aa21b60128b8be7271ab379ec81d47db6 platform-shells/browser/worker_page_entry.ts
77
+ 37ffd4b0a9438be03db9aa2d5cbb1f94489025fee3b46876707f726b6cf82456 peer-office/src/runtime/live_correspondence_desk.ts
78
78
  3b0e179a5fd3cde234903eedbadf591d103fafeffdf169d47d7a771130884fba adapter/proto/nomos/runtime/v2/records_desk_pb.js
79
79
  3c092b8d4185badd23ecf4552434d05aa541b0cd0d534781d687db55260d5da8 adapter/proto/nomos/runtime/v2/sealing_desk_pb.js
80
80
  3c923a87cfaf9815b2801fe9ebe5720889a3eba04e2588dbf7f761aa0eb66a24 peer-office/src/runtime/custody_receipts.ts
@@ -114,7 +114,6 @@
114
114
  511c208c41516891173332c5348ee1d846c886919ace3e9deedeafc1225d6e95 peer-office/src/runtime/kernel_call_scope.ts
115
115
  513a0ca639e4d5cbb6ecce90f9668ab63f5e8ce4df2468b1ad439112b903ef0a platform-shells/node/local-development/kernel_work_recovery.ts
116
116
  519afa7759c5cce91b66cd6b1444014ead77df1f691d0eee356b14206d32d59e peer-office/src/runtime/workspace_call_binding.ts
117
- 534d11140e7e6aa5ca4b8882f56ab3ac72add80ea410a8e521be0273dd8e64a5 peer-office/package/package.json
118
117
  56879b505b84ec7830fce9423473b1f61922cb35ab950d39b10cdf5b9113aa0a adapter/proto/nomos/kernel/v1/kernel_pb.js
119
118
  56879b505b84ec7830fce9423473b1f61922cb35ab950d39b10cdf5b9113aa0a peer-office/package/src/protocol/nomos/kernel/v1/kernel_pb.js
120
119
  56e2ac380c2d9be43647d88928727c17df70a3e734834a5be62c8bcb18616738 adapter/proto/nomos/runtime/v2/custody_desk_pb.js
@@ -208,7 +207,6 @@
208
207
  9c4c967ea6c149011acb8aabfbadb73651f84d572335c48391d627e5283c0cd0 node_modules/@bufbuild/protobuf/dist/esm/fields.js
209
208
  9e1bf39540fd14df32aa2307c44dd4d93a40a6024199f334ccf3db001f44a7f6 peer-office/src/runtime/local_copy_readability.ts
210
209
  9e82e1fc1bfd3e3573f64349dc42b4b624ed61d24e5c553f2bb4d041444f166c node_modules/@bjorn3/browser_wasi_shim/dist/fd.js
211
- 9f55335f6f7332d15988db9a0d1f314fdc4a82da96f08d07e846bb68792ae055 peer-office/src/runtime/workspace_sync.ts
212
210
  a0fcc6110f1154fd197a8ce056e2008dbc7d1750f8dd3ba77c3910af928ed3a1 node_modules/uri-js/dist/es5/uri.all.js
213
211
  a2869f50cbb840c1b0fa9e628b27426f9008ad1e0218685a7d129bcae15b7db9 peer-office/package/runner/build.ts
214
212
  a33120feed1faf765328722cee117f63e2147cb87052120fdacc9bd1086e67ab peer-office/src/runtime/receiving_group_framework_wire.generated.ts
@@ -271,6 +269,7 @@ cdb1f7869edc7171b689fd532fcaa4fa039680e1af44b32cce227cf61ca3fe05 node_modules/@
271
269
  ce9ba4862b010b1d01f2ea9846ac397188526c750e7bb9d437b9ee9dd563b37d peer-office/src/runtime/custodian_placement.ts
272
270
  cfc517180b5ade4339146bacf2ccd624770e071e00b601bd193422c2edbcabe6 node_modules/@bufbuild/protobuf/dist/esm/registry.js
273
271
  d06f53be0045dda3189ec55be539f37536166898b4e7dfd8aa4b6ee8406c4884 peer-office/src/runtime/offer_readiness_desk.ts
272
+ d11c21a188c62572689c1e2ea15f7b61919342ed4609f1a8288627da15c9f9eb peer-office/package/package.json
274
273
  d12b4694d7472ac029b2844cea2d850126085000fdbe5739482773d70e81dcbb peer-office/src/runtime/live_stream_server.ts
275
274
  d13d77a3ef4461782e678f9c4f9227be039f00233de69b1742e1922a84becadc peer-office/src/reception/typescript_application_desk.ts
276
275
  d1f73b0742c76b91aef4e20312062c2367a816de294d60f821bef2de58599413 peer-office/src/runtime/workspace_address.ts
@@ -330,6 +329,7 @@ f924465afc8098350f6ab77065360dce0b01876d1fb3061101e94ce745e25985 peer-office/sr
330
329
  fa2838d141fba0e8ee5bd2197956c3f6b1d23668be2c8841a585614ea7051f99 node_modules/@nodable/entities/src/entityTries.js
331
330
  facc9ec7ab1b104848a8fdc2c517a564c45c8b0e6794a84e48e91fca4cc916ee peer-office/src/runtime/timeline_trace.ts
332
331
  fbc88bbf3cea189f0494b0949049ffeac334b8c5015ebfc988217f2fcdb3262b node_modules/@bufbuild/protobuf/dist/esm/wkt/gen/google/protobuf/duration_pb.js
332
+ fbf55ce167117f1c12bcf0d1a74e3a788e5888bc33dfaf6fc92db7744dbed63b peer-office/src/runtime/workspace_sync.ts
333
333
  fd19ecbd12f0555c762fe07d53452721e7f52e26b3b59c45c6e5579a9ae381f6 peer-office/src/runtime/current_law.ts
334
334
  fe1678ab1c98db7387bea6892ec10a90a06a8e2ed01efb1ee577c3d155e4a395 node_modules/is-unsafe/src/contexts/log.js
335
335
  fe3e2b20c1ebb57c3b390c8f685ad1e04e6f493517fa7e432f4351bb77a1a4d0 node_modules/ieee754/index.js
@@ -17959,7 +17959,7 @@ var NomosRuntimeComponent = (() => {
17959
17959
  }
17960
17960
 
17961
17961
  // ../src/runtime/runtime_identity.ts
17962
- var PEER_RUNTIME_IDENTITY = "0.119.31" ? `@githolon/runtime@${"0.119.31"}` : "@githolon/runtime@unbundled";
17962
+ var PEER_RUNTIME_IDENTITY = "0.119.33" ? `@githolon/runtime@${"0.119.33"}` : "@githolon/runtime@unbundled";
17963
17963
 
17964
17964
  // ../src/runtime/replica_follow_desk.ts
17965
17965
  var REPLICA_FOLLOW_NAMESPACE = "nomos.peer-desk.replica-follow/v2";
@@ -19426,6 +19426,10 @@ var NomosRuntimeComponent = (() => {
19426
19426
  return new TextDecoder().decode(bytes.subarray(0, CLOSE_REASON_BYTES)).replace(/\uFFFD+$/, "");
19427
19427
  }
19428
19428
  var LIVE_CARRIED_COMMITS_BYTES = 4 * 1024 * 1024;
19429
+ function offerFrameBytes(batch) {
19430
+ const offers = batch.source.case === "inline" ? batch.source.value.offers : [];
19431
+ return batch.evidencePack.byteLength + offers.reduce((total, offer) => total + offer.changeUsda.byteLength + offer.commitOid.length + offer.session.length + 16, 0) + 1024;
19432
+ }
19429
19433
  var LIVE_ANSWER_WINDOW = 15000000000n;
19430
19434
  var LIVE_STREAM_WINDOW = 16;
19431
19435
  var LIVE_BATCH_COMMITS = 64;
@@ -19540,8 +19544,7 @@ var NomosRuntimeComponent = (() => {
19540
19544
  send: (workspace, message) => {
19541
19545
  const link = this.#links.get(workspace);
19542
19546
  if (!link || link.state !== "open" || link.publisher) return false;
19543
- this.#send(link, message);
19544
- return true;
19547
+ return this.#send(link, message);
19545
19548
  },
19546
19549
  // This copy's main as its kernel holds it (residency is not asked: a stream ask only ever
19547
19550
  // comes from a procedure that has the copy open).
@@ -19831,10 +19834,17 @@ var NomosRuntimeComponent = (() => {
19831
19834
  this.#effect(link, { case: "openUrl", value: `${endpoint}/v2/workspaces/${encodeURIComponent(link.binding.workspace)}/subscribe?${subscribeQuery(link)}` });
19832
19835
  return true;
19833
19836
  }
19837
+ /** Sends one frame, or refuses one too large for the live socket (large recovery uses Git) and
19838
+ * answers false: the caller must not account a refused frame as sent. An offers frame is refused
19839
+ * on its byte-length estimate, before it is encoded; the encoded size is the backstop. */
19834
19840
  #send(link, message) {
19841
+ if (message.case === "offers" && offerFrameBytes(create(CustodyOfferBatchRequestSchema, message.value)) > MAX_LIVE_FRAME_BYTES) {
19842
+ return false;
19843
+ }
19835
19844
  const bytes = toBinary(LiveOfferFrameSchema, create(LiveOfferFrameSchema, { message }));
19836
- if (bytes.byteLength > MAX_LIVE_FRAME_BYTES) return;
19845
+ if (bytes.byteLength > MAX_LIVE_FRAME_BYTES) return false;
19837
19846
  this.#effect(link, { case: "send", value: bytes });
19847
+ return true;
19838
19848
  }
19839
19849
  export(binding, base, requestId, options = {}) {
19840
19850
  if (this.kernel.isResident(binding.workspace) === false) {
@@ -19858,11 +19868,7 @@ var NomosRuntimeComponent = (() => {
19858
19868
  }
19859
19869
  }
19860
19870
  const batchRequestId = `${binding.replicaId}:${batchHead}`;
19861
- if (intents.length) {
19862
- this.#own.commits(binding.workspace, intents.map((intent) => intent.oid));
19863
- this.#own.request(binding.workspace, batchRequestId, batchHead);
19864
- }
19865
- return create(CustodyOfferBatchRequestSchema, {
19871
+ const batch = create(CustodyOfferBatchRequestSchema, {
19866
19872
  protocolVersion: 2,
19867
19873
  requestId: batchRequestId,
19868
19874
  source: { case: "inline", value: { offers: intents.map((intent) => ({
@@ -19877,6 +19883,15 @@ var NomosRuntimeComponent = (() => {
19877
19883
  // travel the same way.
19878
19884
  evidencePack: options.carryCommits || intents.some((intent) => intent.transportRequirement === IntentTransportRequirement.COMMIT_TREE) ? this.kernel.packDelta(mount, requestId, batchHead, base) : new Uint8Array()
19879
19885
  });
19886
+ if (!options.registerWhenSent) this.#ownBatch(binding.workspace, batch);
19887
+ return batch;
19888
+ }
19889
+ /** Records a batch this replica offered, so the custodian's answer to it is recognised as its own. */
19890
+ #ownBatch(workspace, batch) {
19891
+ const offers = batch.source.case === "inline" ? batch.source.value.offers : [];
19892
+ if (!offers.length) return;
19893
+ this.#own.commits(workspace, offers.map((offer) => offer.commitOid));
19894
+ this.#own.request(workspace, batch.requestId, offers.at(-1).commitOid);
19880
19895
  }
19881
19896
  receive(receipt) {
19882
19897
  const link = [...this.#links.values()].find((item) => item.id === receipt.connectionId);
@@ -20064,6 +20079,10 @@ var NomosRuntimeComponent = (() => {
20064
20079
  link.convergeDue = void 0;
20065
20080
  link.heldRing = void 0;
20066
20081
  }
20082
+ this.#followNow(workspace);
20083
+ }
20084
+ /** Asks for the ordinary (HTTP) round for this workspace now. */
20085
+ #followNow(workspace) {
20067
20086
  if (this.declined) this.declined(workspace);
20068
20087
  else this.remoteAdvanced?.(workspace);
20069
20088
  }
@@ -20225,19 +20244,31 @@ var NomosRuntimeComponent = (() => {
20225
20244
  link.binding,
20226
20245
  continuesAfter ?? answered2,
20227
20246
  ++this.#requestId,
20228
- { baseInHistory: continuesAfter !== void 0, carryCommits: false }
20247
+ { baseInHistory: continuesAfter !== void 0, carryCommits: false, registerWhenSent: true }
20229
20248
  ) : this.#fittingBatch(link, continuesAfter ?? answered2, continuesAfter !== void 0);
20230
20249
  if (batch.evidencePack.byteLength > LIVE_CARRIED_COMMITS_BYTES && !link.publisher) {
20231
20250
  batch = create(CustodyOfferBatchRequestSchema, { ...batch, evidencePack: new Uint8Array() });
20232
20251
  }
20252
+ let refused = false;
20233
20253
  if (batch.source.case === "inline" && batch.source.value.offers.length) {
20234
- this.#send(link, { case: "offers", value: link.publisher ? batch : create(CustodyOfferBatchRequestSchema, {
20254
+ refused = !this.#send(link, { case: "offers", value: link.publisher ? batch : create(CustodyOfferBatchRequestSchema, {
20235
20255
  ...batch,
20236
20256
  baseHead: fence,
20237
20257
  fastForwardOnly: true,
20238
20258
  ...continuesAfter ? { continuesAfter } : {}
20239
20259
  }) });
20240
- if (!link.publisher && head) {
20260
+ if (!refused) this.#ownBatch(link.binding.workspace, batch);
20261
+ else if (!link.publisher) {
20262
+ this.#followNow(link.binding.workspace);
20263
+ } else {
20264
+ this.#send(link, { case: "offers", value: create(CustodyOfferBatchRequestSchema, {
20265
+ protocolVersion: 2,
20266
+ requestId: batch.requestId,
20267
+ source: { case: "inline", value: { offers: [] } },
20268
+ ...head ? { observedHead: head } : {}
20269
+ }) });
20270
+ }
20271
+ if (!refused && !link.publisher && head) {
20241
20272
  const batchHead = batch.source.value.offers.at(-1).commitOid;
20242
20273
  link.stream ??= { sent: batchHead, unanswered: [] };
20243
20274
  link.stream.sent = batchHead;
@@ -20289,8 +20320,9 @@ var NomosRuntimeComponent = (() => {
20289
20320
  /**
20290
20321
  * A follower's next batch above `base`: up to the link's commit bound, cut down until its carried
20291
20322
  * commits fit LIVE_CARRIED_COMMITS_BYTES and its frame fits MAX_LIVE_FRAME_BYTES. A single commit
20292
- * too large to carry still goes out (the custodian admits it on its own commits). Each attempt is
20293
- * the same bounded export, so every batch still continues its base with no hole below it.
20323
+ * too large to carry still goes out (the custodian admits it on its own commits); a single commit
20324
+ * whose frame cannot fit is refused by #send before it is encoded. Each attempt is the same bounded
20325
+ * export, so every batch still continues its base with no hole below it.
20294
20326
  */
20295
20327
  #fittingBatch(link, base, baseInHistory) {
20296
20328
  let bound = link.batchCommits ?? LIVE_BATCH_COMMITS;
@@ -20299,12 +20331,13 @@ var NomosRuntimeComponent = (() => {
20299
20331
  link.binding,
20300
20332
  base,
20301
20333
  ++this.#requestId,
20302
- { baseInHistory, carryCommits: true, maxCommits: bound }
20334
+ { baseInHistory, carryCommits: true, maxCommits: bound, registerWhenSent: true }
20303
20335
  );
20304
20336
  const offers = batch.source.case === "inline" ? batch.source.value.offers : [];
20305
- const frameBytes = batch.evidencePack.byteLength + offers.reduce((total, offer) => total + offer.changeUsda.byteLength + offer.commitOid.length + offer.session.length + 16, 0) + 1024;
20337
+ const frameBytes = offerFrameBytes(batch);
20306
20338
  if (offers.length > 1 && (batch.evidencePack.byteLength > LIVE_CARRIED_COMMITS_BYTES || frameBytes > MAX_LIVE_FRAME_BYTES)) {
20307
- bound = Math.max(1, Math.floor(offers.length / 2));
20339
+ const first = offers[0];
20340
+ bound = first.changeUsda.byteLength + first.commitOid.length + first.session.length + 16 + 1024 > MAX_LIVE_FRAME_BYTES ? 1 : Math.max(1, Math.floor(offers.length / 2));
20308
20341
  link.batchCommits = bound;
20309
20342
  continue;
20310
20343
  }
@@ -21376,6 +21409,7 @@ var NomosRuntimeComponent = (() => {
21376
21409
  var MAX_NOT_CONTAINED = 1024;
21377
21410
  var NOT_CONTAINED_REFUSALS = /* @__PURE__ */ new Set(["nomos.stream.off_main", "nomos.stream.history_required"]);
21378
21411
  var MAX_REBASES_PER_ROUND = 2;
21412
+ var OFF_CHAIN_BASE = /intents_above: base \S* is not on the first-parent chain/;
21379
21413
  var elapsedMillis = (clock2, started) => {
21380
21414
  const finished = clock2.monotonicNanoseconds();
21381
21415
  return finished >= started ? Number(finished - started) / 1e6 : 0;
@@ -22667,7 +22701,7 @@ var NomosRuntimeComponent = (() => {
22667
22701
  const head = this.#kernel.head(this.#mount, this.#requestId);
22668
22702
  if (tracked !== candidateHead || !head || head === tracked) return void 0;
22669
22703
  if (candidateHead === this.#rebaseFrom) return void 0;
22670
- if (this.#kernel.transportIntentsAbove(this.#mount, this.#requestId, 0n, tracked, this.#offerHead).intents.length === 0) return void 0;
22704
+ if (!this.#holdsWorkAbove(tracked)) return void 0;
22671
22705
  this.#rebases += 1;
22672
22706
  this.#offerAfterConverge = false;
22673
22707
  this.#previousHead = tracked;
@@ -22678,6 +22712,23 @@ var NomosRuntimeComponent = (() => {
22678
22712
  this.#candidateDurable = true;
22679
22713
  return this.#offerOrReconcile();
22680
22714
  }
22715
+ /**
22716
+ * Whether the head this round offers holds at least one commit above `base`. Asks for the ONE
22717
+ * commit immediately above base (the bounded `fromBase` walk the live export uses): a walk of
22718
+ * commit objects to base plus one decoded change, never the whole suffix. Asking for the whole
22719
+ * suffix only to test it for emptiness decoded every unsent change (5,001 commits: 3.6 s and
22720
+ * 70.6 MB). A base off that head's first-parent chain (a dependency's captured prefix the
22721
+ * rebase rewrote, or history that ends before base) is no fast-forward from base: there is
22722
+ * nothing to offer onto it in this round, and the next round plans from the rebased head.
22723
+ */
22724
+ #holdsWorkAbove(base) {
22725
+ try {
22726
+ return this.#kernel.transportIntentsAbove(this.#mount, this.#requestId, 1n, base, this.#offerHead, true).intents.length > 0;
22727
+ } catch (error) {
22728
+ if (error instanceof Error && OFF_CHAIN_BASE.test(error.message)) return false;
22729
+ throw error;
22730
+ }
22731
+ }
22681
22732
  /**
22682
22733
  * The admitted local changes a copy with a missing history commit holds above the provider's last
22683
22734
  * admitted head (its bookmark), oldest first. Without a reachable bookmark the walk ends at the
@@ -284,7 +284,7 @@
284
284
  }
285
285
 
286
286
  // ../../platform-shells/browser/worker_page_entry.ts
287
- var workerDigest = true ? "4f8c79d9c411cfaf065f0e73e92706fdd2c9da10e549b646c6e554e4e6ab987f" : "";
287
+ var workerDigest = true ? "d24a79a523b9fac2983f4cd1fb19e3b4e38e5bdec73489d23aa8b024c34df155" : "";
288
288
  var SLOW_OPERATION_MICROS = 1e6;
289
289
  var slowOperationsReported = 0;
290
290
  var bootStages = [];
@@ -27421,7 +27421,7 @@
27421
27421
  // ../src/runtime/runtime_identity.ts
27422
27422
  init_define_NOMOS_KERNEL_RELEASE();
27423
27423
  init_shims();
27424
- var PEER_RUNTIME_IDENTITY = "0.119.31" ? `@githolon/runtime@${"0.119.31"}` : "@githolon/runtime@unbundled";
27424
+ var PEER_RUNTIME_IDENTITY = "0.119.33" ? `@githolon/runtime@${"0.119.33"}` : "@githolon/runtime@unbundled";
27425
27425
 
27426
27426
  // ../src/runtime/replica_follow_desk.ts
27427
27427
  init_define_NOMOS_KERNEL_RELEASE();
@@ -28977,6 +28977,10 @@
28977
28977
  return new TextDecoder().decode(bytes.subarray(0, CLOSE_REASON_BYTES)).replace(/\uFFFD+$/, "");
28978
28978
  }
28979
28979
  var LIVE_CARRIED_COMMITS_BYTES = 4 * 1024 * 1024;
28980
+ function offerFrameBytes(batch) {
28981
+ const offers = batch.source.case === "inline" ? batch.source.value.offers : [];
28982
+ return batch.evidencePack.byteLength + offers.reduce((total, offer) => total + offer.changeUsda.byteLength + offer.commitOid.length + offer.session.length + 16, 0) + 1024;
28983
+ }
28980
28984
  var LIVE_ANSWER_WINDOW = 15000000000n;
28981
28985
  var LIVE_STREAM_WINDOW = 16;
28982
28986
  var LIVE_BATCH_COMMITS = 64;
@@ -29036,7 +29040,7 @@
29036
29040
  };
29037
29041
  _commits = new WeakMap();
29038
29042
  _requests = new WeakMap();
29039
- var _links, _own, _progress, _progressOwedSince, _recounting, _walks, _sequence12, _requestId3, _closures, _LiveCorrespondenceDesk_instances, recordClosure_fn, closeByRuntime_fn, count_fn, chain_fn, walksOf_fn, custodyDeepened_fn, holds_fn, heldPeerMain_fn, cursor_fn, currentCursor_fn, effect_fn, open_fn2, send_fn, admitted_fn, declined_fn, announced_fn, releaseHeldRing_fn, placementAnnounced_fn, outcomesDigest_fn, outcomesAnnounced_fn, outcomesArrived_fn, fittingBatch_fn;
29043
+ var _links, _own, _progress, _progressOwedSince, _recounting, _walks, _sequence12, _requestId3, _closures, _LiveCorrespondenceDesk_instances, recordClosure_fn, closeByRuntime_fn, count_fn, chain_fn, walksOf_fn, custodyDeepened_fn, holds_fn, heldPeerMain_fn, cursor_fn, currentCursor_fn, effect_fn, open_fn2, send_fn, ownBatch_fn, admitted_fn, declined_fn, followNow_fn, announced_fn, releaseHeldRing_fn, placementAnnounced_fn, outcomesDigest_fn, outcomesAnnounced_fn, outcomesArrived_fn, fittingBatch_fn;
29040
29044
  var LiveCorrespondenceDesk = class {
29041
29045
  constructor(kernel, events, clock2, relayOrigin, staging, lawTrees) {
29042
29046
  __privateAdd(this, _LiveCorrespondenceDesk_instances);
@@ -29099,8 +29103,7 @@
29099
29103
  send: (workspace, message) => {
29100
29104
  const link = __privateGet(this, _links).get(workspace);
29101
29105
  if (!link || link.state !== "open" || link.publisher) return false;
29102
- __privateMethod(this, _LiveCorrespondenceDesk_instances, send_fn).call(this, link, message);
29103
- return true;
29106
+ return __privateMethod(this, _LiveCorrespondenceDesk_instances, send_fn).call(this, link, message);
29104
29107
  },
29105
29108
  // This copy's main as its kernel holds it (residency is not asked: a stream ask only ever
29106
29109
  // comes from a procedure that has the copy open).
@@ -29251,11 +29254,7 @@
29251
29254
  }
29252
29255
  }
29253
29256
  const batchRequestId = `${binding.replicaId}:${batchHead}`;
29254
- if (intents.length) {
29255
- __privateGet(this, _own).commits(binding.workspace, intents.map((intent) => intent.oid));
29256
- __privateGet(this, _own).request(binding.workspace, batchRequestId, batchHead);
29257
- }
29258
- return create(CustodyOfferBatchRequestSchema, {
29257
+ const batch = create(CustodyOfferBatchRequestSchema, {
29259
29258
  protocolVersion: 2,
29260
29259
  requestId: batchRequestId,
29261
29260
  source: { case: "inline", value: { offers: intents.map((intent) => ({
@@ -29270,6 +29269,8 @@
29270
29269
  // travel the same way.
29271
29270
  evidencePack: options.carryCommits || intents.some((intent) => intent.transportRequirement === IntentTransportRequirement.COMMIT_TREE) ? this.kernel.packDelta(mount, requestId, batchHead, base) : new Uint8Array()
29272
29271
  });
29272
+ if (!options.registerWhenSent) __privateMethod(this, _LiveCorrespondenceDesk_instances, ownBatch_fn).call(this, binding.workspace, batch);
29273
+ return batch;
29273
29274
  }
29274
29275
  receive(receipt) {
29275
29276
  const link = [...__privateGet(this, _links).values()].find((item) => item.id === receipt.connectionId);
@@ -29424,19 +29425,31 @@
29424
29425
  link.binding,
29425
29426
  continuesAfter ?? answered2,
29426
29427
  ++__privateWrapper(this, _requestId3)._,
29427
- { baseInHistory: continuesAfter !== void 0, carryCommits: false }
29428
+ { baseInHistory: continuesAfter !== void 0, carryCommits: false, registerWhenSent: true }
29428
29429
  ) : __privateMethod(this, _LiveCorrespondenceDesk_instances, fittingBatch_fn).call(this, link, continuesAfter ?? answered2, continuesAfter !== void 0);
29429
29430
  if (batch.evidencePack.byteLength > LIVE_CARRIED_COMMITS_BYTES && !link.publisher) {
29430
29431
  batch = create(CustodyOfferBatchRequestSchema, { ...batch, evidencePack: new Uint8Array() });
29431
29432
  }
29433
+ let refused = false;
29432
29434
  if (batch.source.case === "inline" && batch.source.value.offers.length) {
29433
- __privateMethod(this, _LiveCorrespondenceDesk_instances, send_fn).call(this, link, { case: "offers", value: link.publisher ? batch : create(CustodyOfferBatchRequestSchema, {
29435
+ refused = !__privateMethod(this, _LiveCorrespondenceDesk_instances, send_fn).call(this, link, { case: "offers", value: link.publisher ? batch : create(CustodyOfferBatchRequestSchema, {
29434
29436
  ...batch,
29435
29437
  baseHead: fence,
29436
29438
  fastForwardOnly: true,
29437
29439
  ...continuesAfter ? { continuesAfter } : {}
29438
29440
  }) });
29439
- if (!link.publisher && head) {
29441
+ if (!refused) __privateMethod(this, _LiveCorrespondenceDesk_instances, ownBatch_fn).call(this, link.binding.workspace, batch);
29442
+ else if (!link.publisher) {
29443
+ __privateMethod(this, _LiveCorrespondenceDesk_instances, followNow_fn).call(this, link.binding.workspace);
29444
+ } else {
29445
+ __privateMethod(this, _LiveCorrespondenceDesk_instances, send_fn).call(this, link, { case: "offers", value: create(CustodyOfferBatchRequestSchema, {
29446
+ protocolVersion: 2,
29447
+ requestId: batch.requestId,
29448
+ source: { case: "inline", value: { offers: [] } },
29449
+ ...head ? { observedHead: head } : {}
29450
+ }) });
29451
+ }
29452
+ if (!refused && !link.publisher && head) {
29440
29453
  const batchHead = batch.source.value.offers.at(-1).commitOid;
29441
29454
  link.stream ?? (link.stream = { sent: batchHead, unanswered: [] });
29442
29455
  link.stream.sent = batchHead;
@@ -29659,10 +29672,24 @@
29659
29672
  __privateMethod(this, _LiveCorrespondenceDesk_instances, effect_fn).call(this, link, { case: "openUrl", value: `${endpoint}/v2/workspaces/${encodeURIComponent(link.binding.workspace)}/subscribe?${subscribeQuery(link)}` });
29660
29673
  return true;
29661
29674
  };
29675
+ /** Sends one frame, or refuses one too large for the live socket (large recovery uses Git) and
29676
+ * answers false: the caller must not account a refused frame as sent. An offers frame is refused
29677
+ * on its byte-length estimate, before it is encoded; the encoded size is the backstop. */
29662
29678
  send_fn = function(link, message) {
29679
+ if (message.case === "offers" && offerFrameBytes(create(CustodyOfferBatchRequestSchema, message.value)) > MAX_LIVE_FRAME_BYTES) {
29680
+ return false;
29681
+ }
29663
29682
  const bytes = toBinary(LiveOfferFrameSchema, create(LiveOfferFrameSchema, { message }));
29664
- if (bytes.byteLength > MAX_LIVE_FRAME_BYTES) return;
29683
+ if (bytes.byteLength > MAX_LIVE_FRAME_BYTES) return false;
29665
29684
  __privateMethod(this, _LiveCorrespondenceDesk_instances, effect_fn).call(this, link, { case: "send", value: bytes });
29685
+ return true;
29686
+ };
29687
+ /** Records a batch this replica offered, so the custodian's answer to it is recognised as its own. */
29688
+ ownBatch_fn = function(workspace, batch) {
29689
+ const offers = batch.source.case === "inline" ? batch.source.value.offers : [];
29690
+ if (!offers.length) return;
29691
+ __privateGet(this, _own).commits(workspace, offers.map((offer) => offer.commitOid));
29692
+ __privateGet(this, _own).request(workspace, batch.requestId, offers.at(-1).commitOid);
29666
29693
  };
29667
29694
  /**
29668
29695
  * The custodian judged a live batch. Admission acknowledges the batch at once; its admitted main
@@ -29768,6 +29795,10 @@
29768
29795
  link.convergeDue = void 0;
29769
29796
  link.heldRing = void 0;
29770
29797
  }
29798
+ __privateMethod(this, _LiveCorrespondenceDesk_instances, followNow_fn).call(this, workspace);
29799
+ };
29800
+ /** Asks for the ordinary (HTTP) round for this workspace now. */
29801
+ followNow_fn = function(workspace) {
29771
29802
  if (this.declined) this.declined(workspace);
29772
29803
  else this.remoteAdvanced?.(workspace);
29773
29804
  };
@@ -29861,8 +29892,9 @@
29861
29892
  /**
29862
29893
  * A follower's next batch above `base`: up to the link's commit bound, cut down until its carried
29863
29894
  * commits fit LIVE_CARRIED_COMMITS_BYTES and its frame fits MAX_LIVE_FRAME_BYTES. A single commit
29864
- * too large to carry still goes out (the custodian admits it on its own commits). Each attempt is
29865
- * the same bounded export, so every batch still continues its base with no hole below it.
29895
+ * too large to carry still goes out (the custodian admits it on its own commits); a single commit
29896
+ * whose frame cannot fit is refused by #send before it is encoded. Each attempt is the same bounded
29897
+ * export, so every batch still continues its base with no hole below it.
29866
29898
  */
29867
29899
  fittingBatch_fn = function(link, base, baseInHistory) {
29868
29900
  let bound = link.batchCommits ?? LIVE_BATCH_COMMITS;
@@ -29871,12 +29903,13 @@
29871
29903
  link.binding,
29872
29904
  base,
29873
29905
  ++__privateWrapper(this, _requestId3)._,
29874
- { baseInHistory, carryCommits: true, maxCommits: bound }
29906
+ { baseInHistory, carryCommits: true, maxCommits: bound, registerWhenSent: true }
29875
29907
  );
29876
29908
  const offers = batch.source.case === "inline" ? batch.source.value.offers : [];
29877
- const frameBytes = batch.evidencePack.byteLength + offers.reduce((total, offer) => total + offer.changeUsda.byteLength + offer.commitOid.length + offer.session.length + 16, 0) + 1024;
29909
+ const frameBytes = offerFrameBytes(batch);
29878
29910
  if (offers.length > 1 && (batch.evidencePack.byteLength > LIVE_CARRIED_COMMITS_BYTES || frameBytes > MAX_LIVE_FRAME_BYTES)) {
29879
- bound = Math.max(1, Math.floor(offers.length / 2));
29911
+ const first = offers[0];
29912
+ bound = first.changeUsda.byteLength + first.commitOid.length + first.session.length + 16 + 1024 > MAX_LIVE_FRAME_BYTES ? 1 : Math.max(1, Math.floor(offers.length / 2));
29880
29913
  link.batchCommits = bound;
29881
29914
  continue;
29882
29915
  }
@@ -31025,11 +31058,12 @@
31025
31058
  var MAX_NOT_CONTAINED = 1024;
31026
31059
  var NOT_CONTAINED_REFUSALS = /* @__PURE__ */ new Set(["nomos.stream.off_main", "nomos.stream.history_required"]);
31027
31060
  var MAX_REBASES_PER_ROUND = 2;
31061
+ var OFF_CHAIN_BASE = /intents_above: base \S* is not on the first-parent chain/;
31028
31062
  var elapsedMillis = (clock2, started) => {
31029
31063
  const finished = clock2.monotonicNanoseconds();
31030
31064
  return finished >= started ? Number(finished - started) / 1e6 : 0;
31031
31065
  };
31032
- var _kernel19, _credentials4, _clock14, _mount2, _binding, _route2, _rediscover, _reroute, _discoveredFrontier, _observePlacement, _recheckPlacement, _directoryAnswered, _placementFetched, _acquired, _streamSequence, _historySlices, _levelling, _roundStartHead, _levelledBatches, _levelledBytes, _boundaries, _sealedObserved, _command2, _requestId6, _started, _state, _localHead, _offerHead, _previousHead, _pushMillis, _pushBytes, _desiredHead, _candidateDurable, _admissionSummary, _offerReceipt, _pushError, _current3, _lastReceiptEffectId2, _offerSequence, _lastStep2, _probeOnly, _liveConnected, _liveAdmitted, _establishedBase, _completeHistory, _lawProductsImported, _lawProductsInFlight, _shallowMounted, _fetchedLawProducts, _needsReconciliation, _offerAfterConverge, _rebaseFrom, _rebases, _remountsLost, _containment, _containmentProven, _containedBookmark, _parkedLocal, _replaceLocalHead, _repairMissingCommit, _receiveStep, _offered, _lawTrees, _wholeAsked, _receiveSteps, _importId, _importSource, _WorkspaceSyncWork_instances, openRound_fn, mayBeContained_fn, custodianMainOffLocalChain_fn, askContainment_fn, contained_fn, notContained_fn, offerOrReconcile_fn, establishBase_fn, missingTrackedBase_fn, holdsLocalWork_fn, holdsUnsyncedCommits_fn, pullBeforeOffer_fn, acquire_fn, lawProductsFetch_fn, streamEffect_fn, acceptStream_fn, importStep_fn, imported_fn, historyOrMount_fn, remount_fn, remountLost_fn, beginOffer_fn, acceptOffer_fn, placementFrontier_fn, placementOnly_fn, acceptDiscovery_fn, providerCustody_fn, mountFetched_fn, lawProductsRequest_fn, acceptLawProducts_fn, providerCustodyMounted_fn, importLawProducts_fn, converge_fn2, convergeStep_fn, unrelatedLineageRefusal_fn, replaceLocal_fn, converged_fn, offerAfterRebase_fn, preservedSuffix_fn, offerPreserved_fn, preservedCopy_fn, alreadyJudged_fn, rememberJudgment_fn, forgetJudgment_fn, present_fn, finishOfferOutcome_fn, finishWarming_fn, transportFailure_fn, remember_fn4, finish_fn2, cloudBase_fn, offerEndpoint_fn, workspaceEndpoint_fn, authToken_fn;
31066
+ var _kernel19, _credentials4, _clock14, _mount2, _binding, _route2, _rediscover, _reroute, _discoveredFrontier, _observePlacement, _recheckPlacement, _directoryAnswered, _placementFetched, _acquired, _streamSequence, _historySlices, _levelling, _roundStartHead, _levelledBatches, _levelledBytes, _boundaries, _sealedObserved, _command2, _requestId6, _started, _state, _localHead, _offerHead, _previousHead, _pushMillis, _pushBytes, _desiredHead, _candidateDurable, _admissionSummary, _offerReceipt, _pushError, _current3, _lastReceiptEffectId2, _offerSequence, _lastStep2, _probeOnly, _liveConnected, _liveAdmitted, _establishedBase, _completeHistory, _lawProductsImported, _lawProductsInFlight, _shallowMounted, _fetchedLawProducts, _needsReconciliation, _offerAfterConverge, _rebaseFrom, _rebases, _remountsLost, _containment, _containmentProven, _containedBookmark, _parkedLocal, _replaceLocalHead, _repairMissingCommit, _receiveStep, _offered, _lawTrees, _wholeAsked, _receiveSteps, _importId, _importSource, _WorkspaceSyncWork_instances, openRound_fn, mayBeContained_fn, custodianMainOffLocalChain_fn, askContainment_fn, contained_fn, notContained_fn, offerOrReconcile_fn, establishBase_fn, missingTrackedBase_fn, holdsLocalWork_fn, holdsUnsyncedCommits_fn, pullBeforeOffer_fn, acquire_fn, lawProductsFetch_fn, streamEffect_fn, acceptStream_fn, importStep_fn, imported_fn, historyOrMount_fn, remount_fn, remountLost_fn, beginOffer_fn, acceptOffer_fn, placementFrontier_fn, placementOnly_fn, acceptDiscovery_fn, providerCustody_fn, mountFetched_fn, lawProductsRequest_fn, acceptLawProducts_fn, providerCustodyMounted_fn, importLawProducts_fn, converge_fn2, convergeStep_fn, unrelatedLineageRefusal_fn, replaceLocal_fn, converged_fn, offerAfterRebase_fn, holdsWorkAbove_fn, preservedSuffix_fn, offerPreserved_fn, preservedCopy_fn, alreadyJudged_fn, rememberJudgment_fn, forgetJudgment_fn, present_fn, finishOfferOutcome_fn, finishWarming_fn, transportFailure_fn, remember_fn4, finish_fn2, cloudBase_fn, offerEndpoint_fn, workspaceEndpoint_fn, authToken_fn;
31033
31067
  var WorkspaceSyncWork = class {
31034
31068
  constructor(args) {
31035
31069
  __privateAdd(this, _WorkspaceSyncWork_instances);
@@ -32346,7 +32380,7 @@
32346
32380
  const head = __privateGet(this, _kernel19).head(__privateGet(this, _mount2), __privateGet(this, _requestId6));
32347
32381
  if (tracked !== candidateHead || !head || head === tracked) return void 0;
32348
32382
  if (candidateHead === __privateGet(this, _rebaseFrom)) return void 0;
32349
- if (__privateGet(this, _kernel19).transportIntentsAbove(__privateGet(this, _mount2), __privateGet(this, _requestId6), 0n, tracked, __privateGet(this, _offerHead)).intents.length === 0) return void 0;
32383
+ if (!__privateMethod(this, _WorkspaceSyncWork_instances, holdsWorkAbove_fn).call(this, tracked)) return void 0;
32350
32384
  __privateSet(this, _rebases, __privateGet(this, _rebases) + 1);
32351
32385
  __privateSet(this, _offerAfterConverge, false);
32352
32386
  __privateSet(this, _previousHead, tracked);
@@ -32357,6 +32391,23 @@
32357
32391
  __privateSet(this, _candidateDurable, true);
32358
32392
  return __privateMethod(this, _WorkspaceSyncWork_instances, offerOrReconcile_fn).call(this);
32359
32393
  };
32394
+ /**
32395
+ * Whether the head this round offers holds at least one commit above `base`. Asks for the ONE
32396
+ * commit immediately above base (the bounded `fromBase` walk the live export uses): a walk of
32397
+ * commit objects to base plus one decoded change, never the whole suffix. Asking for the whole
32398
+ * suffix only to test it for emptiness decoded every unsent change (5,001 commits: 3.6 s and
32399
+ * 70.6 MB). A base off that head's first-parent chain (a dependency's captured prefix the
32400
+ * rebase rewrote, or history that ends before base) is no fast-forward from base: there is
32401
+ * nothing to offer onto it in this round, and the next round plans from the rebased head.
32402
+ */
32403
+ holdsWorkAbove_fn = function(base) {
32404
+ try {
32405
+ return __privateGet(this, _kernel19).transportIntentsAbove(__privateGet(this, _mount2), __privateGet(this, _requestId6), 1n, base, __privateGet(this, _offerHead), true).intents.length > 0;
32406
+ } catch (error) {
32407
+ if (error instanceof Error && OFF_CHAIN_BASE.test(error.message)) return false;
32408
+ throw error;
32409
+ }
32410
+ };
32360
32411
  /**
32361
32412
  * The admitted local changes a copy with a missing history commit holds above the provider's last
32362
32413
  * admitted head (its bookmark), oldest first. Without a reachable bookmark the walk ends at the
@@ -27684,7 +27684,7 @@
27684
27684
  // ../src/runtime/runtime_identity.ts
27685
27685
  init_define_NOMOS_KERNEL_RELEASE();
27686
27686
  init_shims();
27687
- var PEER_RUNTIME_IDENTITY = "0.119.31" ? `@githolon/runtime@${"0.119.31"}` : "@githolon/runtime@unbundled";
27687
+ var PEER_RUNTIME_IDENTITY = "0.119.33" ? `@githolon/runtime@${"0.119.33"}` : "@githolon/runtime@unbundled";
27688
27688
 
27689
27689
  // ../src/runtime/replica_follow_desk.ts
27690
27690
  init_define_NOMOS_KERNEL_RELEASE();
@@ -29234,6 +29234,10 @@
29234
29234
  return new TextDecoder().decode(bytes.subarray(0, CLOSE_REASON_BYTES)).replace(/\uFFFD+$/, "");
29235
29235
  }
29236
29236
  var LIVE_CARRIED_COMMITS_BYTES = 4 * 1024 * 1024;
29237
+ function offerFrameBytes(batch) {
29238
+ const offers = batch.source.case === "inline" ? batch.source.value.offers : [];
29239
+ return batch.evidencePack.byteLength + offers.reduce((total, offer) => total + offer.changeUsda.byteLength + offer.commitOid.length + offer.session.length + 16, 0) + 1024;
29240
+ }
29237
29241
  var LIVE_ANSWER_WINDOW = 15000000000n;
29238
29242
  var LIVE_STREAM_WINDOW = 16;
29239
29243
  var LIVE_BATCH_COMMITS = 64;
@@ -29293,7 +29297,7 @@
29293
29297
  };
29294
29298
  _commits = new WeakMap();
29295
29299
  _requests = new WeakMap();
29296
- var _links, _own, _progress, _progressOwedSince, _recounting, _walks, _sequence12, _requestId3, _closures, _LiveCorrespondenceDesk_instances, recordClosure_fn, closeByRuntime_fn, count_fn, chain_fn, walksOf_fn, custodyDeepened_fn, holds_fn, heldPeerMain_fn, cursor_fn, currentCursor_fn, effect_fn, open_fn2, send_fn, admitted_fn, declined_fn, announced_fn, releaseHeldRing_fn, placementAnnounced_fn, outcomesDigest_fn, outcomesAnnounced_fn, outcomesArrived_fn, fittingBatch_fn;
29300
+ var _links, _own, _progress, _progressOwedSince, _recounting, _walks, _sequence12, _requestId3, _closures, _LiveCorrespondenceDesk_instances, recordClosure_fn, closeByRuntime_fn, count_fn, chain_fn, walksOf_fn, custodyDeepened_fn, holds_fn, heldPeerMain_fn, cursor_fn, currentCursor_fn, effect_fn, open_fn2, send_fn, ownBatch_fn, admitted_fn, declined_fn, followNow_fn, announced_fn, releaseHeldRing_fn, placementAnnounced_fn, outcomesDigest_fn, outcomesAnnounced_fn, outcomesArrived_fn, fittingBatch_fn;
29297
29301
  var LiveCorrespondenceDesk = class {
29298
29302
  constructor(kernel, events, clock2, relayOrigin, staging, lawTrees) {
29299
29303
  __privateAdd(this, _LiveCorrespondenceDesk_instances);
@@ -29356,8 +29360,7 @@
29356
29360
  send: (workspace, message) => {
29357
29361
  const link = __privateGet(this, _links).get(workspace);
29358
29362
  if (!link || link.state !== "open" || link.publisher) return false;
29359
- __privateMethod(this, _LiveCorrespondenceDesk_instances, send_fn).call(this, link, message);
29360
- return true;
29363
+ return __privateMethod(this, _LiveCorrespondenceDesk_instances, send_fn).call(this, link, message);
29361
29364
  },
29362
29365
  // This copy's main as its kernel holds it (residency is not asked: a stream ask only ever
29363
29366
  // comes from a procedure that has the copy open).
@@ -29508,11 +29511,7 @@
29508
29511
  }
29509
29512
  }
29510
29513
  const batchRequestId = `${binding.replicaId}:${batchHead}`;
29511
- if (intents.length) {
29512
- __privateGet(this, _own).commits(binding.workspace, intents.map((intent) => intent.oid));
29513
- __privateGet(this, _own).request(binding.workspace, batchRequestId, batchHead);
29514
- }
29515
- return create(CustodyOfferBatchRequestSchema, {
29514
+ const batch = create(CustodyOfferBatchRequestSchema, {
29516
29515
  protocolVersion: 2,
29517
29516
  requestId: batchRequestId,
29518
29517
  source: { case: "inline", value: { offers: intents.map((intent) => ({
@@ -29527,6 +29526,8 @@
29527
29526
  // travel the same way.
29528
29527
  evidencePack: options.carryCommits || intents.some((intent) => intent.transportRequirement === IntentTransportRequirement.COMMIT_TREE) ? this.kernel.packDelta(mount, requestId, batchHead, base) : new Uint8Array()
29529
29528
  });
29529
+ if (!options.registerWhenSent) __privateMethod(this, _LiveCorrespondenceDesk_instances, ownBatch_fn).call(this, binding.workspace, batch);
29530
+ return batch;
29530
29531
  }
29531
29532
  receive(receipt) {
29532
29533
  const link = [...__privateGet(this, _links).values()].find((item) => item.id === receipt.connectionId);
@@ -29681,19 +29682,31 @@
29681
29682
  link.binding,
29682
29683
  continuesAfter ?? answered2,
29683
29684
  ++__privateWrapper(this, _requestId3)._,
29684
- { baseInHistory: continuesAfter !== void 0, carryCommits: false }
29685
+ { baseInHistory: continuesAfter !== void 0, carryCommits: false, registerWhenSent: true }
29685
29686
  ) : __privateMethod(this, _LiveCorrespondenceDesk_instances, fittingBatch_fn).call(this, link, continuesAfter ?? answered2, continuesAfter !== void 0);
29686
29687
  if (batch.evidencePack.byteLength > LIVE_CARRIED_COMMITS_BYTES && !link.publisher) {
29687
29688
  batch = create(CustodyOfferBatchRequestSchema, { ...batch, evidencePack: new Uint8Array() });
29688
29689
  }
29690
+ let refused = false;
29689
29691
  if (batch.source.case === "inline" && batch.source.value.offers.length) {
29690
- __privateMethod(this, _LiveCorrespondenceDesk_instances, send_fn).call(this, link, { case: "offers", value: link.publisher ? batch : create(CustodyOfferBatchRequestSchema, {
29692
+ refused = !__privateMethod(this, _LiveCorrespondenceDesk_instances, send_fn).call(this, link, { case: "offers", value: link.publisher ? batch : create(CustodyOfferBatchRequestSchema, {
29691
29693
  ...batch,
29692
29694
  baseHead: fence,
29693
29695
  fastForwardOnly: true,
29694
29696
  ...continuesAfter ? { continuesAfter } : {}
29695
29697
  }) });
29696
- if (!link.publisher && head) {
29698
+ if (!refused) __privateMethod(this, _LiveCorrespondenceDesk_instances, ownBatch_fn).call(this, link.binding.workspace, batch);
29699
+ else if (!link.publisher) {
29700
+ __privateMethod(this, _LiveCorrespondenceDesk_instances, followNow_fn).call(this, link.binding.workspace);
29701
+ } else {
29702
+ __privateMethod(this, _LiveCorrespondenceDesk_instances, send_fn).call(this, link, { case: "offers", value: create(CustodyOfferBatchRequestSchema, {
29703
+ protocolVersion: 2,
29704
+ requestId: batch.requestId,
29705
+ source: { case: "inline", value: { offers: [] } },
29706
+ ...head ? { observedHead: head } : {}
29707
+ }) });
29708
+ }
29709
+ if (!refused && !link.publisher && head) {
29697
29710
  const batchHead = batch.source.value.offers.at(-1).commitOid;
29698
29711
  link.stream ?? (link.stream = { sent: batchHead, unanswered: [] });
29699
29712
  link.stream.sent = batchHead;
@@ -29916,10 +29929,24 @@
29916
29929
  __privateMethod(this, _LiveCorrespondenceDesk_instances, effect_fn).call(this, link, { case: "openUrl", value: `${endpoint}/v2/workspaces/${encodeURIComponent(link.binding.workspace)}/subscribe?${subscribeQuery(link)}` });
29917
29930
  return true;
29918
29931
  };
29932
+ /** Sends one frame, or refuses one too large for the live socket (large recovery uses Git) and
29933
+ * answers false: the caller must not account a refused frame as sent. An offers frame is refused
29934
+ * on its byte-length estimate, before it is encoded; the encoded size is the backstop. */
29919
29935
  send_fn = function(link, message) {
29936
+ if (message.case === "offers" && offerFrameBytes(create(CustodyOfferBatchRequestSchema, message.value)) > MAX_LIVE_FRAME_BYTES) {
29937
+ return false;
29938
+ }
29920
29939
  const bytes = toBinary(LiveOfferFrameSchema, create(LiveOfferFrameSchema, { message }));
29921
- if (bytes.byteLength > MAX_LIVE_FRAME_BYTES) return;
29940
+ if (bytes.byteLength > MAX_LIVE_FRAME_BYTES) return false;
29922
29941
  __privateMethod(this, _LiveCorrespondenceDesk_instances, effect_fn).call(this, link, { case: "send", value: bytes });
29942
+ return true;
29943
+ };
29944
+ /** Records a batch this replica offered, so the custodian's answer to it is recognised as its own. */
29945
+ ownBatch_fn = function(workspace, batch) {
29946
+ const offers = batch.source.case === "inline" ? batch.source.value.offers : [];
29947
+ if (!offers.length) return;
29948
+ __privateGet(this, _own).commits(workspace, offers.map((offer) => offer.commitOid));
29949
+ __privateGet(this, _own).request(workspace, batch.requestId, offers.at(-1).commitOid);
29923
29950
  };
29924
29951
  /**
29925
29952
  * The custodian judged a live batch. Admission acknowledges the batch at once; its admitted main
@@ -30025,6 +30052,10 @@
30025
30052
  link.convergeDue = void 0;
30026
30053
  link.heldRing = void 0;
30027
30054
  }
30055
+ __privateMethod(this, _LiveCorrespondenceDesk_instances, followNow_fn).call(this, workspace);
30056
+ };
30057
+ /** Asks for the ordinary (HTTP) round for this workspace now. */
30058
+ followNow_fn = function(workspace) {
30028
30059
  if (this.declined) this.declined(workspace);
30029
30060
  else this.remoteAdvanced?.(workspace);
30030
30061
  };
@@ -30118,8 +30149,9 @@
30118
30149
  /**
30119
30150
  * A follower's next batch above `base`: up to the link's commit bound, cut down until its carried
30120
30151
  * commits fit LIVE_CARRIED_COMMITS_BYTES and its frame fits MAX_LIVE_FRAME_BYTES. A single commit
30121
- * too large to carry still goes out (the custodian admits it on its own commits). Each attempt is
30122
- * the same bounded export, so every batch still continues its base with no hole below it.
30152
+ * too large to carry still goes out (the custodian admits it on its own commits); a single commit
30153
+ * whose frame cannot fit is refused by #send before it is encoded. Each attempt is the same bounded
30154
+ * export, so every batch still continues its base with no hole below it.
30123
30155
  */
30124
30156
  fittingBatch_fn = function(link, base, baseInHistory) {
30125
30157
  let bound = link.batchCommits ?? LIVE_BATCH_COMMITS;
@@ -30128,12 +30160,13 @@
30128
30160
  link.binding,
30129
30161
  base,
30130
30162
  ++__privateWrapper(this, _requestId3)._,
30131
- { baseInHistory, carryCommits: true, maxCommits: bound }
30163
+ { baseInHistory, carryCommits: true, maxCommits: bound, registerWhenSent: true }
30132
30164
  );
30133
30165
  const offers = batch.source.case === "inline" ? batch.source.value.offers : [];
30134
- const frameBytes = batch.evidencePack.byteLength + offers.reduce((total, offer) => total + offer.changeUsda.byteLength + offer.commitOid.length + offer.session.length + 16, 0) + 1024;
30166
+ const frameBytes = offerFrameBytes(batch);
30135
30167
  if (offers.length > 1 && (batch.evidencePack.byteLength > LIVE_CARRIED_COMMITS_BYTES || frameBytes > MAX_LIVE_FRAME_BYTES)) {
30136
- bound = Math.max(1, Math.floor(offers.length / 2));
30168
+ const first = offers[0];
30169
+ bound = first.changeUsda.byteLength + first.commitOid.length + first.session.length + 16 + 1024 > MAX_LIVE_FRAME_BYTES ? 1 : Math.max(1, Math.floor(offers.length / 2));
30137
30170
  link.batchCommits = bound;
30138
30171
  continue;
30139
30172
  }
@@ -31282,11 +31315,12 @@
31282
31315
  var MAX_NOT_CONTAINED = 1024;
31283
31316
  var NOT_CONTAINED_REFUSALS = /* @__PURE__ */ new Set(["nomos.stream.off_main", "nomos.stream.history_required"]);
31284
31317
  var MAX_REBASES_PER_ROUND = 2;
31318
+ var OFF_CHAIN_BASE = /intents_above: base \S* is not on the first-parent chain/;
31285
31319
  var elapsedMillis = (clock2, started) => {
31286
31320
  const finished = clock2.monotonicNanoseconds();
31287
31321
  return finished >= started ? Number(finished - started) / 1e6 : 0;
31288
31322
  };
31289
- var _kernel19, _credentials4, _clock14, _mount2, _binding, _route2, _rediscover, _reroute, _discoveredFrontier, _observePlacement, _recheckPlacement, _directoryAnswered, _placementFetched, _acquired, _streamSequence, _historySlices, _levelling, _roundStartHead, _levelledBatches, _levelledBytes, _boundaries, _sealedObserved, _command2, _requestId6, _started, _state, _localHead, _offerHead, _previousHead, _pushMillis, _pushBytes, _desiredHead, _candidateDurable, _admissionSummary, _offerReceipt, _pushError, _current3, _lastReceiptEffectId2, _offerSequence, _lastStep2, _probeOnly, _liveConnected, _liveAdmitted, _establishedBase, _completeHistory, _lawProductsImported, _lawProductsInFlight, _shallowMounted, _fetchedLawProducts, _needsReconciliation, _offerAfterConverge, _rebaseFrom, _rebases, _remountsLost, _containment, _containmentProven, _containedBookmark, _parkedLocal, _replaceLocalHead, _repairMissingCommit, _receiveStep, _offered, _lawTrees, _wholeAsked, _receiveSteps, _importId, _importSource, _WorkspaceSyncWork_instances, openRound_fn, mayBeContained_fn, custodianMainOffLocalChain_fn, askContainment_fn, contained_fn, notContained_fn, offerOrReconcile_fn, establishBase_fn, missingTrackedBase_fn, holdsLocalWork_fn, holdsUnsyncedCommits_fn, pullBeforeOffer_fn, acquire_fn, lawProductsFetch_fn, streamEffect_fn, acceptStream_fn, importStep_fn, imported_fn, historyOrMount_fn, remount_fn, remountLost_fn, beginOffer_fn, acceptOffer_fn, placementFrontier_fn, placementOnly_fn, acceptDiscovery_fn, providerCustody_fn, mountFetched_fn, lawProductsRequest_fn, acceptLawProducts_fn, providerCustodyMounted_fn, importLawProducts_fn, converge_fn2, convergeStep_fn, unrelatedLineageRefusal_fn, replaceLocal_fn, converged_fn, offerAfterRebase_fn, preservedSuffix_fn, offerPreserved_fn, preservedCopy_fn, alreadyJudged_fn, rememberJudgment_fn, forgetJudgment_fn, present_fn, finishOfferOutcome_fn, finishWarming_fn, transportFailure_fn, remember_fn4, finish_fn2, cloudBase_fn, offerEndpoint_fn, workspaceEndpoint_fn, authToken_fn;
31323
+ var _kernel19, _credentials4, _clock14, _mount2, _binding, _route2, _rediscover, _reroute, _discoveredFrontier, _observePlacement, _recheckPlacement, _directoryAnswered, _placementFetched, _acquired, _streamSequence, _historySlices, _levelling, _roundStartHead, _levelledBatches, _levelledBytes, _boundaries, _sealedObserved, _command2, _requestId6, _started, _state, _localHead, _offerHead, _previousHead, _pushMillis, _pushBytes, _desiredHead, _candidateDurable, _admissionSummary, _offerReceipt, _pushError, _current3, _lastReceiptEffectId2, _offerSequence, _lastStep2, _probeOnly, _liveConnected, _liveAdmitted, _establishedBase, _completeHistory, _lawProductsImported, _lawProductsInFlight, _shallowMounted, _fetchedLawProducts, _needsReconciliation, _offerAfterConverge, _rebaseFrom, _rebases, _remountsLost, _containment, _containmentProven, _containedBookmark, _parkedLocal, _replaceLocalHead, _repairMissingCommit, _receiveStep, _offered, _lawTrees, _wholeAsked, _receiveSteps, _importId, _importSource, _WorkspaceSyncWork_instances, openRound_fn, mayBeContained_fn, custodianMainOffLocalChain_fn, askContainment_fn, contained_fn, notContained_fn, offerOrReconcile_fn, establishBase_fn, missingTrackedBase_fn, holdsLocalWork_fn, holdsUnsyncedCommits_fn, pullBeforeOffer_fn, acquire_fn, lawProductsFetch_fn, streamEffect_fn, acceptStream_fn, importStep_fn, imported_fn, historyOrMount_fn, remount_fn, remountLost_fn, beginOffer_fn, acceptOffer_fn, placementFrontier_fn, placementOnly_fn, acceptDiscovery_fn, providerCustody_fn, mountFetched_fn, lawProductsRequest_fn, acceptLawProducts_fn, providerCustodyMounted_fn, importLawProducts_fn, converge_fn2, convergeStep_fn, unrelatedLineageRefusal_fn, replaceLocal_fn, converged_fn, offerAfterRebase_fn, holdsWorkAbove_fn, preservedSuffix_fn, offerPreserved_fn, preservedCopy_fn, alreadyJudged_fn, rememberJudgment_fn, forgetJudgment_fn, present_fn, finishOfferOutcome_fn, finishWarming_fn, transportFailure_fn, remember_fn4, finish_fn2, cloudBase_fn, offerEndpoint_fn, workspaceEndpoint_fn, authToken_fn;
31290
31324
  var WorkspaceSyncWork = class {
31291
31325
  constructor(args) {
31292
31326
  __privateAdd(this, _WorkspaceSyncWork_instances);
@@ -32603,7 +32637,7 @@
32603
32637
  const head = __privateGet(this, _kernel19).head(__privateGet(this, _mount2), __privateGet(this, _requestId6));
32604
32638
  if (tracked !== candidateHead || !head || head === tracked) return void 0;
32605
32639
  if (candidateHead === __privateGet(this, _rebaseFrom)) return void 0;
32606
- if (__privateGet(this, _kernel19).transportIntentsAbove(__privateGet(this, _mount2), __privateGet(this, _requestId6), 0n, tracked, __privateGet(this, _offerHead)).intents.length === 0) return void 0;
32640
+ if (!__privateMethod(this, _WorkspaceSyncWork_instances, holdsWorkAbove_fn).call(this, tracked)) return void 0;
32607
32641
  __privateSet(this, _rebases, __privateGet(this, _rebases) + 1);
32608
32642
  __privateSet(this, _offerAfterConverge, false);
32609
32643
  __privateSet(this, _previousHead, tracked);
@@ -32614,6 +32648,23 @@
32614
32648
  __privateSet(this, _candidateDurable, true);
32615
32649
  return __privateMethod(this, _WorkspaceSyncWork_instances, offerOrReconcile_fn).call(this);
32616
32650
  };
32651
+ /**
32652
+ * Whether the head this round offers holds at least one commit above `base`. Asks for the ONE
32653
+ * commit immediately above base (the bounded `fromBase` walk the live export uses): a walk of
32654
+ * commit objects to base plus one decoded change, never the whole suffix. Asking for the whole
32655
+ * suffix only to test it for emptiness decoded every unsent change (5,001 commits: 3.6 s and
32656
+ * 70.6 MB). A base off that head's first-parent chain (a dependency's captured prefix the
32657
+ * rebase rewrote, or history that ends before base) is no fast-forward from base: there is
32658
+ * nothing to offer onto it in this round, and the next round plans from the rebased head.
32659
+ */
32660
+ holdsWorkAbove_fn = function(base) {
32661
+ try {
32662
+ return __privateGet(this, _kernel19).transportIntentsAbove(__privateGet(this, _mount2), __privateGet(this, _requestId6), 1n, base, __privateGet(this, _offerHead), true).intents.length > 0;
32663
+ } catch (error) {
32664
+ if (error instanceof Error && OFF_CHAIN_BASE.test(error.message)) return false;
32665
+ throw error;
32666
+ }
32667
+ };
32617
32668
  /**
32618
32669
  * The admitted local changes a copy with a missing history commit holds above the provider's last
32619
32670
  * admitted head (its bookmark), oldest first. Without a reachable bookmark the walk ends at the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@githolon/runtime",
3
- "version": "0.119.31",
3
+ "version": "0.119.33",
4
4
  "type": "module",
5
5
  "description": "The portable Nomos application runtime, reception contracts, and Node/browser runners.",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -26258,7 +26258,7 @@ function delayUntilDue(follow, nowUnixMillis) {
26258
26258
 
26259
26259
  // ../src/runtime/runtime_identity.ts
26260
26260
  init_define_NOMOS_KERNEL_RELEASE();
26261
- var PEER_RUNTIME_IDENTITY = "0.119.31" ? `@githolon/runtime@${"0.119.31"}` : "@githolon/runtime@unbundled";
26261
+ var PEER_RUNTIME_IDENTITY = "0.119.33" ? `@githolon/runtime@${"0.119.33"}` : "@githolon/runtime@unbundled";
26262
26262
 
26263
26263
  // ../src/runtime/replica_follow_desk.ts
26264
26264
  init_define_NOMOS_KERNEL_RELEASE();
@@ -27740,6 +27740,10 @@ function boundedReason(reason) {
27740
27740
  return new TextDecoder().decode(bytes.subarray(0, CLOSE_REASON_BYTES)).replace(/\uFFFD+$/, "");
27741
27741
  }
27742
27742
  var LIVE_CARRIED_COMMITS_BYTES = 4 * 1024 * 1024;
27743
+ function offerFrameBytes(batch) {
27744
+ const offers = batch.source.case === "inline" ? batch.source.value.offers : [];
27745
+ return batch.evidencePack.byteLength + offers.reduce((total, offer) => total + offer.changeUsda.byteLength + offer.commitOid.length + offer.session.length + 16, 0) + 1024;
27746
+ }
27743
27747
  var LIVE_ANSWER_WINDOW = 15000000000n;
27744
27748
  var LIVE_STREAM_WINDOW = 16;
27745
27749
  var LIVE_BATCH_COMMITS = 64;
@@ -27854,8 +27858,7 @@ var LiveCorrespondenceDesk = class {
27854
27858
  send: (workspace, message) => {
27855
27859
  const link = this.#links.get(workspace);
27856
27860
  if (!link || link.state !== "open" || link.publisher) return false;
27857
- this.#send(link, message);
27858
- return true;
27861
+ return this.#send(link, message);
27859
27862
  },
27860
27863
  // This copy's main as its kernel holds it (residency is not asked: a stream ask only ever
27861
27864
  // comes from a procedure that has the copy open).
@@ -28145,10 +28148,17 @@ var LiveCorrespondenceDesk = class {
28145
28148
  this.#effect(link, { case: "openUrl", value: `${endpoint}/v2/workspaces/${encodeURIComponent(link.binding.workspace)}/subscribe?${subscribeQuery(link)}` });
28146
28149
  return true;
28147
28150
  }
28151
+ /** Sends one frame, or refuses one too large for the live socket (large recovery uses Git) and
28152
+ * answers false: the caller must not account a refused frame as sent. An offers frame is refused
28153
+ * on its byte-length estimate, before it is encoded; the encoded size is the backstop. */
28148
28154
  #send(link, message) {
28155
+ if (message.case === "offers" && offerFrameBytes(create(CustodyOfferBatchRequestSchema, message.value)) > MAX_LIVE_FRAME_BYTES) {
28156
+ return false;
28157
+ }
28149
28158
  const bytes = toBinary(LiveOfferFrameSchema, create(LiveOfferFrameSchema, { message }));
28150
- if (bytes.byteLength > MAX_LIVE_FRAME_BYTES) return;
28159
+ if (bytes.byteLength > MAX_LIVE_FRAME_BYTES) return false;
28151
28160
  this.#effect(link, { case: "send", value: bytes });
28161
+ return true;
28152
28162
  }
28153
28163
  export(binding, base, requestId, options = {}) {
28154
28164
  if (this.kernel.isResident(binding.workspace) === false) {
@@ -28172,11 +28182,7 @@ var LiveCorrespondenceDesk = class {
28172
28182
  }
28173
28183
  }
28174
28184
  const batchRequestId = `${binding.replicaId}:${batchHead}`;
28175
- if (intents.length) {
28176
- this.#own.commits(binding.workspace, intents.map((intent) => intent.oid));
28177
- this.#own.request(binding.workspace, batchRequestId, batchHead);
28178
- }
28179
- return create(CustodyOfferBatchRequestSchema, {
28185
+ const batch = create(CustodyOfferBatchRequestSchema, {
28180
28186
  protocolVersion: 2,
28181
28187
  requestId: batchRequestId,
28182
28188
  source: { case: "inline", value: { offers: intents.map((intent) => ({
@@ -28191,6 +28197,15 @@ var LiveCorrespondenceDesk = class {
28191
28197
  // travel the same way.
28192
28198
  evidencePack: options.carryCommits || intents.some((intent) => intent.transportRequirement === IntentTransportRequirement.COMMIT_TREE) ? this.kernel.packDelta(mount, requestId, batchHead, base) : new Uint8Array()
28193
28199
  });
28200
+ if (!options.registerWhenSent) this.#ownBatch(binding.workspace, batch);
28201
+ return batch;
28202
+ }
28203
+ /** Records a batch this replica offered, so the custodian's answer to it is recognised as its own. */
28204
+ #ownBatch(workspace, batch) {
28205
+ const offers = batch.source.case === "inline" ? batch.source.value.offers : [];
28206
+ if (!offers.length) return;
28207
+ this.#own.commits(workspace, offers.map((offer) => offer.commitOid));
28208
+ this.#own.request(workspace, batch.requestId, offers.at(-1).commitOid);
28194
28209
  }
28195
28210
  receive(receipt) {
28196
28211
  const link = [...this.#links.values()].find((item) => item.id === receipt.connectionId);
@@ -28378,6 +28393,10 @@ var LiveCorrespondenceDesk = class {
28378
28393
  link.convergeDue = void 0;
28379
28394
  link.heldRing = void 0;
28380
28395
  }
28396
+ this.#followNow(workspace);
28397
+ }
28398
+ /** Asks for the ordinary (HTTP) round for this workspace now. */
28399
+ #followNow(workspace) {
28381
28400
  if (this.declined) this.declined(workspace);
28382
28401
  else this.remoteAdvanced?.(workspace);
28383
28402
  }
@@ -28539,19 +28558,31 @@ var LiveCorrespondenceDesk = class {
28539
28558
  link.binding,
28540
28559
  continuesAfter ?? answered2,
28541
28560
  ++this.#requestId,
28542
- { baseInHistory: continuesAfter !== void 0, carryCommits: false }
28561
+ { baseInHistory: continuesAfter !== void 0, carryCommits: false, registerWhenSent: true }
28543
28562
  ) : this.#fittingBatch(link, continuesAfter ?? answered2, continuesAfter !== void 0);
28544
28563
  if (batch.evidencePack.byteLength > LIVE_CARRIED_COMMITS_BYTES && !link.publisher) {
28545
28564
  batch = create(CustodyOfferBatchRequestSchema, { ...batch, evidencePack: new Uint8Array() });
28546
28565
  }
28566
+ let refused = false;
28547
28567
  if (batch.source.case === "inline" && batch.source.value.offers.length) {
28548
- this.#send(link, { case: "offers", value: link.publisher ? batch : create(CustodyOfferBatchRequestSchema, {
28568
+ refused = !this.#send(link, { case: "offers", value: link.publisher ? batch : create(CustodyOfferBatchRequestSchema, {
28549
28569
  ...batch,
28550
28570
  baseHead: fence,
28551
28571
  fastForwardOnly: true,
28552
28572
  ...continuesAfter ? { continuesAfter } : {}
28553
28573
  }) });
28554
- if (!link.publisher && head) {
28574
+ if (!refused) this.#ownBatch(link.binding.workspace, batch);
28575
+ else if (!link.publisher) {
28576
+ this.#followNow(link.binding.workspace);
28577
+ } else {
28578
+ this.#send(link, { case: "offers", value: create(CustodyOfferBatchRequestSchema, {
28579
+ protocolVersion: 2,
28580
+ requestId: batch.requestId,
28581
+ source: { case: "inline", value: { offers: [] } },
28582
+ ...head ? { observedHead: head } : {}
28583
+ }) });
28584
+ }
28585
+ if (!refused && !link.publisher && head) {
28555
28586
  const batchHead = batch.source.value.offers.at(-1).commitOid;
28556
28587
  link.stream ??= { sent: batchHead, unanswered: [] };
28557
28588
  link.stream.sent = batchHead;
@@ -28603,8 +28634,9 @@ var LiveCorrespondenceDesk = class {
28603
28634
  /**
28604
28635
  * A follower's next batch above `base`: up to the link's commit bound, cut down until its carried
28605
28636
  * commits fit LIVE_CARRIED_COMMITS_BYTES and its frame fits MAX_LIVE_FRAME_BYTES. A single commit
28606
- * too large to carry still goes out (the custodian admits it on its own commits). Each attempt is
28607
- * the same bounded export, so every batch still continues its base with no hole below it.
28637
+ * too large to carry still goes out (the custodian admits it on its own commits); a single commit
28638
+ * whose frame cannot fit is refused by #send before it is encoded. Each attempt is the same bounded
28639
+ * export, so every batch still continues its base with no hole below it.
28608
28640
  */
28609
28641
  #fittingBatch(link, base, baseInHistory) {
28610
28642
  let bound = link.batchCommits ?? LIVE_BATCH_COMMITS;
@@ -28613,12 +28645,13 @@ var LiveCorrespondenceDesk = class {
28613
28645
  link.binding,
28614
28646
  base,
28615
28647
  ++this.#requestId,
28616
- { baseInHistory, carryCommits: true, maxCommits: bound }
28648
+ { baseInHistory, carryCommits: true, maxCommits: bound, registerWhenSent: true }
28617
28649
  );
28618
28650
  const offers = batch.source.case === "inline" ? batch.source.value.offers : [];
28619
- const frameBytes = batch.evidencePack.byteLength + offers.reduce((total, offer) => total + offer.changeUsda.byteLength + offer.commitOid.length + offer.session.length + 16, 0) + 1024;
28651
+ const frameBytes = offerFrameBytes(batch);
28620
28652
  if (offers.length > 1 && (batch.evidencePack.byteLength > LIVE_CARRIED_COMMITS_BYTES || frameBytes > MAX_LIVE_FRAME_BYTES)) {
28621
- bound = Math.max(1, Math.floor(offers.length / 2));
28653
+ const first = offers[0];
28654
+ bound = first.changeUsda.byteLength + first.commitOid.length + first.session.length + 16 + 1024 > MAX_LIVE_FRAME_BYTES ? 1 : Math.max(1, Math.floor(offers.length / 2));
28622
28655
  link.batchCommits = bound;
28623
28656
  continue;
28624
28657
  }
@@ -29708,6 +29741,7 @@ var notContainedThisLifetime = /* @__PURE__ */ new Map();
29708
29741
  var MAX_NOT_CONTAINED = 1024;
29709
29742
  var NOT_CONTAINED_REFUSALS = /* @__PURE__ */ new Set(["nomos.stream.off_main", "nomos.stream.history_required"]);
29710
29743
  var MAX_REBASES_PER_ROUND = 2;
29744
+ var OFF_CHAIN_BASE = /intents_above: base \S* is not on the first-parent chain/;
29711
29745
  var elapsedMillis = (clock2, started) => {
29712
29746
  const finished = clock2.monotonicNanoseconds();
29713
29747
  return finished >= started ? Number(finished - started) / 1e6 : 0;
@@ -30999,7 +31033,7 @@ var WorkspaceSyncWork = class {
30999
31033
  const head = this.#kernel.head(this.#mount, this.#requestId);
31000
31034
  if (tracked !== candidateHead || !head || head === tracked) return void 0;
31001
31035
  if (candidateHead === this.#rebaseFrom) return void 0;
31002
- if (this.#kernel.transportIntentsAbove(this.#mount, this.#requestId, 0n, tracked, this.#offerHead).intents.length === 0) return void 0;
31036
+ if (!this.#holdsWorkAbove(tracked)) return void 0;
31003
31037
  this.#rebases += 1;
31004
31038
  this.#offerAfterConverge = false;
31005
31039
  this.#previousHead = tracked;
@@ -31010,6 +31044,23 @@ var WorkspaceSyncWork = class {
31010
31044
  this.#candidateDurable = true;
31011
31045
  return this.#offerOrReconcile();
31012
31046
  }
31047
+ /**
31048
+ * Whether the head this round offers holds at least one commit above `base`. Asks for the ONE
31049
+ * commit immediately above base (the bounded `fromBase` walk the live export uses): a walk of
31050
+ * commit objects to base plus one decoded change, never the whole suffix. Asking for the whole
31051
+ * suffix only to test it for emptiness decoded every unsent change (5,001 commits: 3.6 s and
31052
+ * 70.6 MB). A base off that head's first-parent chain (a dependency's captured prefix the
31053
+ * rebase rewrote, or history that ends before base) is no fast-forward from base: there is
31054
+ * nothing to offer onto it in this round, and the next round plans from the rebased head.
31055
+ */
31056
+ #holdsWorkAbove(base) {
31057
+ try {
31058
+ return this.#kernel.transportIntentsAbove(this.#mount, this.#requestId, 1n, base, this.#offerHead, true).intents.length > 0;
31059
+ } catch (error) {
31060
+ if (error instanceof Error && OFF_CHAIN_BASE.test(error.message)) return false;
31061
+ throw error;
31062
+ }
31063
+ }
31013
31064
  /**
31014
31065
  * The admitted local changes a copy with a missing history commit holds above the provider's last
31015
31066
  * admitted head (its bookmark), oldest first. Without a reachable bookmark the walk ends at the