@origintrail-official/dkg-agent 10.0.21 → 10.0.23

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.
Files changed (207) hide show
  1. package/dist/approved-private-replica-proof-runs.d.ts +40 -0
  2. package/dist/approved-private-replica-proof-runs.d.ts.map +1 -0
  3. package/dist/approved-private-replica-proof-runs.js +49 -0
  4. package/dist/approved-private-replica-proof-runs.js.map +1 -0
  5. package/dist/approved-private-replica.d.ts +18 -1
  6. package/dist/approved-private-replica.d.ts.map +1 -1
  7. package/dist/approved-private-replica.js +9 -3
  8. package/dist/approved-private-replica.js.map +1 -1
  9. package/dist/context-graph-chain-discovery-binding.d.ts +2 -0
  10. package/dist/context-graph-chain-discovery-binding.d.ts.map +1 -1
  11. package/dist/context-graph-chain-discovery-binding.js +7 -0
  12. package/dist/context-graph-chain-discovery-binding.js.map +1 -1
  13. package/dist/context-graph-dormant-identity.d.ts +8 -0
  14. package/dist/context-graph-dormant-identity.d.ts.map +1 -0
  15. package/dist/context-graph-dormant-identity.js +48 -0
  16. package/dist/context-graph-dormant-identity.js.map +1 -0
  17. package/dist/context-graph-meta-projection.d.ts +19 -55
  18. package/dist/context-graph-meta-projection.d.ts.map +1 -1
  19. package/dist/context-graph-meta-projection.js +94 -46
  20. package/dist/context-graph-meta-projection.js.map +1 -1
  21. package/dist/context-graph-name-binding-target.d.ts +21 -0
  22. package/dist/context-graph-name-binding-target.d.ts.map +1 -0
  23. package/dist/context-graph-name-binding-target.js +68 -0
  24. package/dist/context-graph-name-binding-target.js.map +1 -0
  25. package/dist/context-graph-persisted-name-aliases.d.ts +47 -0
  26. package/dist/context-graph-persisted-name-aliases.d.ts.map +1 -0
  27. package/dist/context-graph-persisted-name-aliases.js +173 -0
  28. package/dist/context-graph-persisted-name-aliases.js.map +1 -0
  29. package/dist/context-graph-read-authority.d.ts +26 -11
  30. package/dist/context-graph-read-authority.d.ts.map +1 -1
  31. package/dist/context-graph-read-authority.js +26 -2
  32. package/dist/context-graph-read-authority.js.map +1 -1
  33. package/dist/context-graph-subscription-authority-recovery.d.ts +4 -0
  34. package/dist/context-graph-subscription-authority-recovery.d.ts.map +1 -1
  35. package/dist/context-graph-subscription-authority-recovery.js +8 -2
  36. package/dist/context-graph-subscription-authority-recovery.js.map +1 -1
  37. package/dist/context-graph-subscription-policy.d.ts +34 -1
  38. package/dist/context-graph-subscription-policy.d.ts.map +1 -1
  39. package/dist/context-graph-subscription-policy.js +143 -1
  40. package/dist/context-graph-subscription-policy.js.map +1 -1
  41. package/dist/curator-meta-refresh.d.ts.map +1 -1
  42. package/dist/curator-meta-refresh.js +31 -9
  43. package/dist/curator-meta-refresh.js.map +1 -1
  44. package/dist/dkg-agent-base.d.ts.map +1 -1
  45. package/dist/dkg-agent-base.js +0 -1
  46. package/dist/dkg-agent-base.js.map +1 -1
  47. package/dist/dkg-agent-cg-name-resolution.d.ts +6 -24
  48. package/dist/dkg-agent-cg-name-resolution.d.ts.map +1 -1
  49. package/dist/dkg-agent-cg-name-resolution.js +42 -58
  50. package/dist/dkg-agent-cg-name-resolution.js.map +1 -1
  51. package/dist/dkg-agent-cg-on-chain-id.d.ts +3 -3
  52. package/dist/dkg-agent-cg-on-chain-id.d.ts.map +1 -1
  53. package/dist/dkg-agent-cg-on-chain-id.js +7 -23
  54. package/dist/dkg-agent-cg-on-chain-id.js.map +1 -1
  55. package/dist/dkg-agent-cg-registry.d.ts +7 -3
  56. package/dist/dkg-agent-cg-registry.d.ts.map +1 -1
  57. package/dist/dkg-agent-cg-registry.js +30 -16
  58. package/dist/dkg-agent-cg-registry.js.map +1 -1
  59. package/dist/dkg-agent-cg-resolve.d.ts +10 -6
  60. package/dist/dkg-agent-cg-resolve.d.ts.map +1 -1
  61. package/dist/dkg-agent-cg-resolve.js +16 -19
  62. package/dist/dkg-agent-cg-resolve.js.map +1 -1
  63. package/dist/dkg-agent-context-graph.d.ts.map +1 -1
  64. package/dist/dkg-agent-context-graph.js +0 -4
  65. package/dist/dkg-agent-context-graph.js.map +1 -1
  66. package/dist/dkg-agent-crypto.d.ts.map +1 -1
  67. package/dist/dkg-agent-crypto.js +53 -57
  68. package/dist/dkg-agent-crypto.js.map +1 -1
  69. package/dist/dkg-agent-lifecycle.d.ts +5 -0
  70. package/dist/dkg-agent-lifecycle.d.ts.map +1 -1
  71. package/dist/dkg-agent-lifecycle.js +156 -133
  72. package/dist/dkg-agent-lifecycle.js.map +1 -1
  73. package/dist/dkg-agent-publish.d.ts.map +1 -1
  74. package/dist/dkg-agent-publish.js +2 -3
  75. package/dist/dkg-agent-publish.js.map +1 -1
  76. package/dist/dkg-agent-query.d.ts.map +1 -1
  77. package/dist/dkg-agent-query.js +12 -9
  78. package/dist/dkg-agent-query.js.map +1 -1
  79. package/dist/dkg-agent-registered-private-empty-vm.d.ts +8 -0
  80. package/dist/dkg-agent-registered-private-empty-vm.d.ts.map +1 -1
  81. package/dist/dkg-agent-registered-private-empty-vm.js +15 -0
  82. package/dist/dkg-agent-registered-private-empty-vm.js.map +1 -1
  83. package/dist/dkg-agent-rfc64-catalog-auto-publish.d.ts.map +1 -1
  84. package/dist/dkg-agent-rfc64-catalog-auto-publish.js +4 -0
  85. package/dist/dkg-agent-rfc64-catalog-auto-publish.js.map +1 -1
  86. package/dist/dkg-agent-rfc64-catalog-upsert.d.ts.map +1 -1
  87. package/dist/dkg-agent-rfc64-catalog-upsert.js +7 -0
  88. package/dist/dkg-agent-rfc64-catalog-upsert.js.map +1 -1
  89. package/dist/dkg-agent-rfc64-catalog.d.ts +4 -0
  90. package/dist/dkg-agent-rfc64-catalog.d.ts.map +1 -1
  91. package/dist/dkg-agent-rfc64-catalog.js +12 -2
  92. package/dist/dkg-agent-rfc64-catalog.js.map +1 -1
  93. package/dist/dkg-agent-rfc64-swm-catalog-projection-supervisor.d.ts +2 -1
  94. package/dist/dkg-agent-rfc64-swm-catalog-projection-supervisor.d.ts.map +1 -1
  95. package/dist/dkg-agent-rfc64-swm-catalog-projection-supervisor.js +23 -15
  96. package/dist/dkg-agent-rfc64-swm-catalog-projection-supervisor.js.map +1 -1
  97. package/dist/dkg-agent-rfc64-swm-catalog-projection.d.ts.map +1 -1
  98. package/dist/dkg-agent-rfc64-swm-catalog-projection.js +3 -0
  99. package/dist/dkg-agent-rfc64-swm-catalog-projection.js.map +1 -1
  100. package/dist/dkg-agent-swm-host.d.ts +13 -22
  101. package/dist/dkg-agent-swm-host.d.ts.map +1 -1
  102. package/dist/dkg-agent-swm-host.js +179 -81
  103. package/dist/dkg-agent-swm-host.js.map +1 -1
  104. package/dist/dkg-agent-swm-substrate.d.ts +2 -0
  105. package/dist/dkg-agent-swm-substrate.d.ts.map +1 -1
  106. package/dist/dkg-agent-swm-substrate.js +5 -9
  107. package/dist/dkg-agent-swm-substrate.js.map +1 -1
  108. package/dist/dkg-agent-types.d.ts +3 -2
  109. package/dist/dkg-agent-types.d.ts.map +1 -1
  110. package/dist/dkg-agent.d.ts +4 -10
  111. package/dist/dkg-agent.d.ts.map +1 -1
  112. package/dist/dkg-agent.js +43 -58
  113. package/dist/dkg-agent.js.map +1 -1
  114. package/dist/index.d.ts +1 -1
  115. package/dist/index.d.ts.map +1 -1
  116. package/dist/index.js.map +1 -1
  117. package/dist/internal/context-graph-authority/context-graph-agent-gate-authority.d.ts +6 -1
  118. package/dist/internal/context-graph-authority/context-graph-agent-gate-authority.d.ts.map +1 -1
  119. package/dist/internal/context-graph-authority/context-graph-agent-gate-authority.js +5 -5
  120. package/dist/internal/context-graph-authority/context-graph-agent-gate-authority.js.map +1 -1
  121. package/dist/internal/context-graph-authority/context-graph-authority.d.ts +14 -1
  122. package/dist/internal/context-graph-authority/context-graph-authority.d.ts.map +1 -1
  123. package/dist/internal/context-graph-authority/context-graph-authority.js +19 -0
  124. package/dist/internal/context-graph-authority/context-graph-authority.js.map +1 -1
  125. package/dist/internal/context-graph-cache-invalidating-store.d.ts +10 -2
  126. package/dist/internal/context-graph-cache-invalidating-store.d.ts.map +1 -1
  127. package/dist/internal/context-graph-cache-invalidating-store.js +67 -67
  128. package/dist/internal/context-graph-cache-invalidating-store.js.map +1 -1
  129. package/dist/internal/context-graph-meta-record-copy.d.ts +1 -1
  130. package/dist/internal/context-graph-meta-record-copy.d.ts.map +1 -1
  131. package/dist/internal/context-graph-meta-record.d.ts +40 -0
  132. package/dist/internal/context-graph-meta-record.d.ts.map +1 -0
  133. package/dist/internal/context-graph-meta-record.js +3 -0
  134. package/dist/internal/context-graph-meta-record.js.map +1 -0
  135. package/dist/internal/peer-gate-revision.d.ts +28 -0
  136. package/dist/internal/peer-gate-revision.d.ts.map +1 -0
  137. package/dist/internal/peer-gate-revision.js +46 -0
  138. package/dist/internal/peer-gate-revision.js.map +1 -0
  139. package/dist/internal/projection-mutation-observer.d.ts +5 -0
  140. package/dist/internal/projection-mutation-observer.d.ts.map +1 -0
  141. package/dist/internal/projection-mutation-observer.js +24 -0
  142. package/dist/internal/projection-mutation-observer.js.map +1 -0
  143. package/dist/internal/promote/assertion-promote-precommit.d.ts +8 -6
  144. package/dist/internal/promote/assertion-promote-precommit.d.ts.map +1 -1
  145. package/dist/internal/promote/assertion-promote-precommit.js +8 -6
  146. package/dist/internal/promote/assertion-promote-precommit.js.map +1 -1
  147. package/dist/internal/recipient-key-route-fence.d.ts +57 -0
  148. package/dist/internal/recipient-key-route-fence.d.ts.map +1 -0
  149. package/dist/internal/recipient-key-route-fence.js +169 -0
  150. package/dist/internal/recipient-key-route-fence.js.map +1 -0
  151. package/dist/internal/store-mutation.d.ts +28 -0
  152. package/dist/internal/store-mutation.d.ts.map +1 -0
  153. package/dist/internal/store-mutation.js +3 -0
  154. package/dist/internal/store-mutation.js.map +1 -0
  155. package/dist/main-thread-time-slice.d.ts +19 -0
  156. package/dist/main-thread-time-slice.d.ts.map +1 -0
  157. package/dist/main-thread-time-slice.js +32 -0
  158. package/dist/main-thread-time-slice.js.map +1 -0
  159. package/dist/p2p/storage-ack-registrar.d.ts.map +1 -1
  160. package/dist/p2p/storage-ack-registrar.js +3 -5
  161. package/dist/p2p/storage-ack-registrar.js.map +1 -1
  162. package/dist/registered-context-graph-authority.d.ts +17 -0
  163. package/dist/registered-context-graph-authority.d.ts.map +1 -1
  164. package/dist/registered-private-empty-vm-attempt-v1.d.ts.map +1 -1
  165. package/dist/registered-private-empty-vm-attempt-v1.js +8 -4
  166. package/dist/registered-private-empty-vm-attempt-v1.js.map +1 -1
  167. package/dist/rfc64/catalog-repair-retry-v1.d.ts +9 -3
  168. package/dist/rfc64/catalog-repair-retry-v1.d.ts.map +1 -1
  169. package/dist/rfc64/catalog-repair-retry-v1.js +22 -6
  170. package/dist/rfc64/catalog-repair-retry-v1.js.map +1 -1
  171. package/dist/rfc64/control-envelope-signer-v1.d.ts +8 -0
  172. package/dist/rfc64/control-envelope-signer-v1.d.ts.map +1 -1
  173. package/dist/rfc64/control-envelope-signer-v1.js +20 -0
  174. package/dist/rfc64/control-envelope-signer-v1.js.map +1 -1
  175. package/dist/rfc64/legacy-swm-boundary-fence-v1.d.ts +109 -0
  176. package/dist/rfc64/legacy-swm-boundary-fence-v1.d.ts.map +1 -0
  177. package/dist/rfc64/legacy-swm-boundary-fence-v1.js +236 -0
  178. package/dist/rfc64/legacy-swm-boundary-fence-v1.js.map +1 -0
  179. package/dist/rfc64/legacy-swm-boundary-v1.d.ts +28 -1
  180. package/dist/rfc64/legacy-swm-boundary-v1.d.ts.map +1 -1
  181. package/dist/rfc64/legacy-swm-boundary-v1.js +74 -145
  182. package/dist/rfc64/legacy-swm-boundary-v1.js.map +1 -1
  183. package/dist/rfc64/public-catalog-successor-producer-v1.d.ts +2 -0
  184. package/dist/rfc64/public-catalog-successor-producer-v1.d.ts.map +1 -1
  185. package/dist/rfc64/public-catalog-successor-producer-v1.js +77 -33
  186. package/dist/rfc64/public-catalog-successor-producer-v1.js.map +1 -1
  187. package/dist/rfc64/public-catalog-successor-row-binding-v1.d.ts +16 -0
  188. package/dist/rfc64/public-catalog-successor-row-binding-v1.d.ts.map +1 -0
  189. package/dist/rfc64/public-catalog-successor-row-binding-v1.js +28 -0
  190. package/dist/rfc64/public-catalog-successor-row-binding-v1.js.map +1 -0
  191. package/dist/rfc64/swm-inventory-catalog-reconciler-v1.d.ts +6 -0
  192. package/dist/rfc64/swm-inventory-catalog-reconciler-v1.d.ts.map +1 -1
  193. package/dist/rfc64/swm-inventory-catalog-reconciler-v1.js +9 -3
  194. package/dist/rfc64/swm-inventory-catalog-reconciler-v1.js.map +1 -1
  195. package/dist/rfc64/swm-inventory-settlement-outlook-v1.d.ts +8 -0
  196. package/dist/rfc64/swm-inventory-settlement-outlook-v1.d.ts.map +1 -0
  197. package/dist/rfc64/swm-inventory-settlement-outlook-v1.js +32 -0
  198. package/dist/rfc64/swm-inventory-settlement-outlook-v1.js.map +1 -0
  199. package/dist/sync/requester/swm-recovery-apply.d.ts +1 -1
  200. package/dist/sync/requester/swm-recovery-apply.d.ts.map +1 -1
  201. package/dist/sync/requester/swm-recovery-apply.js +0 -1
  202. package/dist/sync/requester/swm-recovery-apply.js.map +1 -1
  203. package/dist/sync/requester/swm-target-executor.d.ts +2 -2
  204. package/dist/sync/requester/swm-target-executor.d.ts.map +1 -1
  205. package/dist/sync/requester/swm-target-executor.js +1 -2
  206. package/dist/sync/requester/swm-target-executor.js.map +1 -1
  207. package/package.json +11 -8
@@ -7,6 +7,9 @@
7
7
  * `this: DKGAgent` so cross-calls resolve against the composed class.
8
8
  */
9
9
  import { orderVmRecoveryCandidates } from './vm-recovery-candidate-order.js';
10
+ import { isCanonicalAuthoritativeContextGraphId, localContextGraphIdMatchesCommittedNameHash, } from './context-graph-binding-state.js';
11
+ import { isAdmittedContextGraphSubscription } from './context-graph-subscription-policy.js';
12
+ import { normalizeContextGraphNameHash } from './context-graph-name-candidate.js';
10
13
  import { createHash } from 'node:crypto';
11
14
  import { createSwmHostModeHandler } from './internal/gossip/host-mode-handler.js';
12
15
  import { Buffer } from 'node:buffer';
@@ -252,6 +255,14 @@ export class SwmHostModeMethods extends DKGAgentBase {
252
255
  this.log.debug(createOperationContext('system'), `Could not seed discovery rate-limit aggregate from disk: ${msg}`);
253
256
  }
254
257
  this.log.info(createOperationContext('system'), `SWM host-mode store initialized at ${join(this.config.dataDir, 'swm-host')} (role=${role})`);
258
+ }
259
+ /** Restore disk intent after the durable subscription admission plan exists. */
260
+ async restoreSwmHostModeSubscriptions() {
261
+ if (!this.swmHostModeStore)
262
+ return;
263
+ const session = this.gossipSession;
264
+ if (session.live() === null)
265
+ return;
255
266
  // OT-RFC-38 LU-6 B3 — restore persisted host-mode subscriptions
256
267
  // BEFORE the chain-event poller starts. Chain events older than
257
268
  // the poller's lookback window would otherwise be silently lost
@@ -261,6 +272,8 @@ export class SwmHostModeMethods extends DKGAgentBase {
261
272
  // shortcut that keeps the per-restart re-derivation cheap.
262
273
  try {
263
274
  const previouslySubscribed = await this.swmHostModeStore.listHostModeSubscribedCgs();
275
+ if (!session.active || this.gossipSession !== session)
276
+ return;
264
277
  if (previouslySubscribed.length > 0) {
265
278
  // OT-RFC-49 WS-A — persisted host-mode subscriptions are curated by
266
279
  // construction (the curated check ran when each was first wired). With
@@ -283,6 +296,10 @@ export class SwmHostModeMethods extends DKGAgentBase {
283
296
  // authority check on every envelope ingest still catches
284
297
  // revocations even if curator state has changed since.
285
298
  try {
299
+ if (!session.active || this.gossipSession !== session)
300
+ return;
301
+ if (!this.automaticSwmHostModeAdmissionAllowed(cgId))
302
+ continue;
286
303
  this.wireSwmHostModeHandler(cgId, SUBSCRIPTION_SOURCES.RECONCILER, true);
287
304
  // Codex PR #620 R2: also re-probe registration state.
288
305
  // Without this, a host-only CG that was registered while
@@ -292,6 +309,9 @@ export class SwmHostModeMethods extends DKGAgentBase {
292
309
  // sees local store graphs, so the periodic reconciler
293
310
  // can't heal it later either.
294
311
  await this.maybeMarkRegisteredForHostMode(cgId);
312
+ if (!session.active || this.gossipSession !== session)
313
+ return;
314
+ this.automaticSwmHostModeAdmissionAllowed(cgId);
295
315
  }
296
316
  catch (err) {
297
317
  const msg = err instanceof Error ? err.message : String(err);
@@ -318,6 +338,8 @@ export class SwmHostModeMethods extends DKGAgentBase {
318
338
  return;
319
339
  if (!this.swmHostModeStore)
320
340
  return;
341
+ if (!this.automaticSwmHostModeAdmissionAllowed(contextGraphId))
342
+ return;
321
343
  if (Object.values(SYSTEM_CONTEXT_GRAPHS).includes(contextGraphId))
322
344
  return;
323
345
  if (!this.rfc64LegacySwmGossipAllowedForContextGraph(contextGraphId)) {
@@ -351,44 +373,30 @@ export class SwmHostModeMethods extends DKGAgentBase {
351
373
  await this.isCuratedForHostMode(contextGraphId)) {
352
374
  // A manually hosted CG can become curated later. Upgrade the cached
353
375
  // classification so the existing handler starts stripping immediately.
354
- if (!session.active || this.gossipSession !== session)
376
+ if (!session.active || this.gossipSession !== session
377
+ || !this.automaticSwmHostModeAdmissionAllowed(contextGraphId)
378
+ || this.swmHostModeAccessPolicy(contextGraphId) === 0)
355
379
  return;
356
380
  session.swmHostModeCurated.set(hostKey, true);
357
381
  }
382
+ if (!session.active || this.gossipSession !== session
383
+ || !this.automaticSwmHostModeAdmissionAllowed(contextGraphId))
384
+ return;
358
385
  await this.maybeMarkRegisteredForHostMode(contextGraphId);
386
+ if (!session.active || this.gossipSession !== session)
387
+ return;
388
+ this.automaticSwmHostModeAdmissionAllowed(contextGraphId);
359
389
  return;
360
390
  }
361
391
  // Only host curated CGs. Public CGs already have plaintext SWM
362
392
  // distribution and don't need an opaque ciphertext custodian.
363
393
  //
364
- // OT-RFC-38 / LU-6 Phase B — three-source curation probe in
365
- // cheapest-first order. The local SPARQL probe (the original
366
- // gate) only finds the access-policy triple for CGs the local
367
- // node CREATED or JOINED with metadata; for a chain-event-
368
- // driven host-only core OR a beacon-driven pre-reg auto-host,
369
- // no local meta exists and `isPrivateContextGraph` returns
370
- // false, stranding the subscription. We supplement it with:
371
- //
372
- // (a) `subscribedContextGraphs[contextGraphId].onChainHash` —
373
- // set ONLY by code paths that already proved curation
374
- // (chain-event handler with accessPolicy==1, beacon
375
- // handler with accessPolicy==BEACON_ACCESS_POLICY_CURATED,
376
- // successful curator-side `registerContextGraph` on a
377
- // curated CG). Cheapest of the three.
378
- // (b) `onChainAccessPolicyCache` — populated by the chain-
379
- // event poller; keyed by on-chain numeric id. Falls
380
- // through to the existing per-CG cache for CGs whose
381
- // cleartext is unknown locally.
382
- //
383
- // Any of the three returning "curated" is sufficient. If all
384
- // three return "not curated", we bail (same as before). The
385
- // probe is shared with `enableSwmHostModeFor` via
386
- // {@link isCuratedForHostMode} so the operator-hatch close
387
- // (OT-RFC-49 WS-A) sees the SAME curation answer as auto-host —
388
- // critically, the host-only-core case where there's no local
389
- // `_meta` and `isPrivateContextGraph` alone returns false.
394
+ // A numeric policy, verified curated beacon or native private metadata
395
+ // proves curation. A name commitment alone does not prove access policy.
390
396
  const curated = await this.isCuratedForHostMode(contextGraphId);
391
- if (!curated || !session.active || this.gossipSession !== session)
397
+ if (!curated || !session.active || this.gossipSession !== session
398
+ || !this.automaticSwmHostModeAdmissionAllowed(contextGraphId)
399
+ || this.swmHostModeAccessPolicy(contextGraphId) === 0)
392
400
  return;
393
401
  // OT-RFC-49 WS-A — the private-ciphertext strip. With `stripCiphertext`
394
402
  // ON (default), a core declines ALL host-mode custody for a curated CG:
@@ -409,7 +417,13 @@ export class SwmHostModeMethods extends DKGAgentBase {
409
417
  }
410
418
  this.wireSwmHostModeHandler(contextGraphId, source, true);
411
419
  await this.awaitHostModePersistence(contextGraphId);
420
+ if (!session.active || this.gossipSession !== session
421
+ || !this.automaticSwmHostModeAdmissionAllowed(contextGraphId))
422
+ return;
412
423
  await this.maybeMarkRegisteredForHostMode(contextGraphId);
424
+ if (!session.active || this.gossipSession !== session
425
+ || !this.automaticSwmHostModeAdmissionAllowed(contextGraphId))
426
+ return;
413
427
  this.log.info(createOperationContext('system'), `SWM host-mode subscription enabled for "${contextGraphId}" (role=core)`);
414
428
  }
415
429
  /**
@@ -422,36 +436,76 @@ export class SwmHostModeMethods extends DKGAgentBase {
422
436
  swmHostModeStripCiphertext() {
423
437
  return this.config.swmHostMode?.stripCiphertext ?? true;
424
438
  }
425
- /**
426
- * OT-RFC-38 / LU-6 Phase B — the three-source curation probe used to decide
427
- * whether a CG warrants host-mode custody, in cheapest-first order:
428
- *
429
- * (a) `subscribedContextGraphs[id].onChainHash` — set ONLY by paths that
430
- * already proved curation (chain-event handler with accessPolicy==1,
431
- * beacon handler with BEACON_ACCESS_POLICY_CURATED, curator-side
432
- * register of a curated CG);
433
- * (b) `onChainId` + `onChainAccessPolicyCache===1` — populated by the
434
- * chain-event poller, keyed by numeric on-chain id;
435
- * (c) `isPrivateContextGraph` — the local `_meta` accessPolicy/allowlist
436
- * read (the original gate; the only one a host-only core CANNOT
437
- * satisfy, since it never holds the cleartext `_meta`).
438
- *
439
- * Any positive ⇒ curated. A probe throw is treated as NOT curated (the same
440
- * bail-out `reconcileSwmHostModeSubscription` had inline). Extracted so the
441
- * OT-RFC-49 WS-A operator-hatch close in {@link enableSwmHostModeFor} sees
442
- * the EXACT same curation answer as the auto-host path — without this, a
443
- * host-only core (no local `_meta`) would fail an `isPrivateContextGraph`-only
444
- * check, leaving the operator override open for precisely the case WS-A
445
- * exists to close.
446
- */
447
- async isCuratedForHostMode(contextGraphId) {
448
- const sub = this.subscribedContextGraphs.get(contextGraphId);
449
- if (sub?.onChainHash)
439
+ /** Exact local identity wins; absent raw wire requests use native routing. */
440
+ swmHostModeLocalId(contextGraphId) {
441
+ if (this.subscribedContextGraphs.has(contextGraphId)
442
+ || this.contextGraphSubscriptionDormancyById.has(contextGraphId))
443
+ return contextGraphId;
444
+ const wireId = normalizeContextGraphNameHash(contextGraphId);
445
+ if (wireId === null)
446
+ return contextGraphId;
447
+ if (this.subscribedContextGraphs.has(wireId)
448
+ || this.contextGraphSubscriptionDormancyById.has(wireId))
449
+ return wireId;
450
+ return this.resolveContextGraphIdAlias(wireId) ?? wireId;
451
+ }
452
+ /** Automatic hosting cannot activate saved intent that admission left dormant. */
453
+ automaticSwmHostModeAdmissionAllowed(contextGraphId) {
454
+ const localId = this.swmHostModeLocalId(contextGraphId);
455
+ if (!this.contextGraphSubscriptionDormancyById.has(localId)
456
+ || isAdmittedContextGraphSubscription(this.subscribedContextGraphs.get(localId)))
450
457
  return true;
451
- if (sub?.onChainId && this.onChainAccessPolicyCache.get(sub.onChainId) === 1)
458
+ const hostKey = this.canonicalSwmHostModeKey(contextGraphId);
459
+ // Refusal of A cannot retire an operator handler or another slot's owner B.
460
+ if (this.swmHostModeSubscribed.get(hostKey) !== SUBSCRIPTION_SOURCES.MANUAL
461
+ && this.wireIdToLocalCgId.get(hostKey) === localId)
462
+ this.unwireSwmHostModeHandler(contextGraphId);
463
+ return false;
464
+ }
465
+ /** Numeric policy is authoritative over metadata and same-hash beacon hints. */
466
+ swmHostModeAccessPolicy(contextGraphId) {
467
+ let sub = this.subscribedContextGraphs.get(this.swmHostModeLocalId(contextGraphId));
468
+ if (!sub?.onChainId && normalizeContextGraphNameHash(contextGraphId) !== null) {
469
+ const owner = this.wireIdToLocalCgId.get(this.canonicalSwmHostModeKey(contextGraphId));
470
+ sub = owner === undefined ? undefined : this.subscribedContextGraphs.get(owner);
471
+ }
472
+ return sub?.onChainId ? this.onChainAccessPolicyCache.get(sub.onChainId) : undefined;
473
+ }
474
+ /** Manual authority uses current identity, not a retired predecessor's status. */
475
+ manualSwmHostModeLocalId(contextGraphId) {
476
+ if (this.subscribedContextGraphs.has(contextGraphId))
477
+ return contextGraphId;
478
+ const wireId = normalizeContextGraphNameHash(contextGraphId);
479
+ if (wireId === null)
480
+ return contextGraphId;
481
+ if (this.subscribedContextGraphs.has(wireId))
482
+ return wireId;
483
+ return this.resolveContextGraphIdAlias(wireId) ?? wireId;
484
+ }
485
+ /** Manual strip-on custody requires this exact routed slot's public proof. */
486
+ isExactPublicManualSwmHostMode(contextGraphId, hostKey) {
487
+ const localId = this.manualSwmHostModeLocalId(contextGraphId);
488
+ const subscription = this.subscribedContextGraphs.get(localId);
489
+ const onChainId = subscription?.onChainId;
490
+ const wireOwner = this.wireIdToLocalCgId.get(hostKey);
491
+ return isCanonicalAuthoritativeContextGraphId(onChainId)
492
+ && normalizeContextGraphNameHash(subscription?.onChainHash) === hostKey
493
+ && localContextGraphIdMatchesCommittedNameHash(localId, hostKey, id => this.isWireIdKeyedSubscription(id))
494
+ && this.canonicalSwmHostModeKey(contextGraphId) === hostKey
495
+ && (wireOwner === undefined || wireOwner === localId)
496
+ && this.onChainAccessPolicyCache.get(onChainId) === 0;
497
+ }
498
+ /** Curation requires actual policy, signed beacon verification or private metadata. */
499
+ async isCuratedForHostMode(contextGraphId) {
500
+ const policy = this.swmHostModeAccessPolicy(contextGraphId);
501
+ if (policy !== undefined)
502
+ return policy === 1;
503
+ if (this.beaconCuratorByWireId.has(this.canonicalSwmHostModeKey(contextGraphId)))
452
504
  return true;
453
505
  try {
454
- return await this.isPrivateContextGraph(contextGraphId);
506
+ const privateMetadata = await this.isPrivateContextGraph(this.swmHostModeLocalId(contextGraphId));
507
+ const currentPolicy = this.swmHostModeAccessPolicy(contextGraphId);
508
+ return currentPolicy === undefined ? privateMetadata : currentPolicy === 1;
455
509
  }
456
510
  catch {
457
511
  return false;
@@ -512,6 +566,9 @@ export class SwmHostModeMethods extends DKGAgentBase {
512
566
  const live = session.live();
513
567
  if (live === null)
514
568
  return;
569
+ if (source !== SUBSCRIPTION_SOURCES.MANUAL
570
+ && !this.automaticSwmHostModeAdmissionAllowed(contextGraphId))
571
+ return;
515
572
  if (!this.rfc64LegacySwmGossipAllowedForContextGraph(contextGraphId)) {
516
573
  const hostKey = this.canonicalSwmHostModeKey(contextGraphId);
517
574
  const hadRuntimeHostState = session.swmHostModeHandlers.has(hostKey)
@@ -559,7 +616,17 @@ export class SwmHostModeMethods extends DKGAgentBase {
559
616
  session.swmHostModeSubscribed.set(wireCgId, source);
560
617
  session.swmHostModeCurated.set(wireCgId, curated);
561
618
  live.manager.subscribe(swmTopic);
562
- const handler = createSwmHostModeHandler(this, this.log, session, contextGraphId, wireCgId);
619
+ const delegate = createSwmHostModeHandler(this, this.log, session, contextGraphId, wireCgId);
620
+ // Manual public custody must remain proven after enable returns or yields.
621
+ // Automatic callbacks retain their existing positive-private admission.
622
+ const handler = source === SUBSCRIPTION_SOURCES.MANUAL
623
+ ? (topic, data, from) => {
624
+ if (this.swmHostModeStripCiphertext()
625
+ && !this.isExactPublicManualSwmHostMode(contextGraphId, wireCgId))
626
+ return;
627
+ delegate(topic, data, from);
628
+ }
629
+ : delegate;
563
630
  session.swmHostModeHandlers.set(wireCgId, handler);
564
631
  live.manager.onMessage(swmTopic, handler);
565
632
  // B3: persist the host-mode designation so a restart re-engages
@@ -2069,9 +2136,11 @@ export class SwmHostModeMethods extends DKGAgentBase {
2069
2136
  }
2070
2137
  }
2071
2138
  const existing = this.subscribedContextGraphs.get(localCgId);
2072
- if (existing === undefined) {
2073
- return this.contextGraphSubscriptionDormancyById.has(localCgId) ? 'dormant' : undefined;
2074
- }
2139
+ if (this.contextGraphSubscriptionDormancyById.has(localCgId)
2140
+ && !isAdmittedContextGraphSubscription(existing))
2141
+ return 'dormant';
2142
+ if (existing === undefined)
2143
+ return undefined;
2075
2144
  if (!existing.subscribed)
2076
2145
  return undefined;
2077
2146
  if (existing.onChainId === undefined) {
@@ -6695,8 +6764,39 @@ export class SwmHostModeMethods extends DKGAgentBase {
6695
6764
  return { subscribed: false, alreadySubscribed: false, hostingEnabled: true, memberMode: true };
6696
6765
  }
6697
6766
  const hostKey = this.canonicalSwmHostModeKey(contextGraphId);
6767
+ const localId = this.manualSwmHostModeLocalId(contextGraphId);
6768
+ const subscription = this.subscribedContextGraphs.get(localId);
6769
+ const onChainId = subscription?.onChainId;
6770
+ const onChainHash = subscription?.onChainHash;
6771
+ const generation = this.contextGraphBindingState.capture(localId);
6772
+ const handler = session.swmHostModeHandlers.get(hostKey);
6773
+ const source = session.swmHostModeSubscribed.get(hostKey);
6774
+ const wireOwner = this.wireIdToLocalCgId.get(hostKey);
6775
+ const requestIsCurrent = () => session.active && this.gossipSession === session
6776
+ && this.manualSwmHostModeLocalId(contextGraphId) === localId
6777
+ && this.subscribedContextGraphs.get(localId) === subscription
6778
+ && subscription?.onChainId === onChainId && subscription?.onChainHash === onChainHash
6779
+ && this.contextGraphBindingState.isGenerationCurrent(localId, generation)
6780
+ && this.canonicalSwmHostModeKey(contextGraphId) === hostKey
6781
+ && this.wireIdToLocalCgId.get(hostKey) === wireOwner;
6698
6782
  const curated = await this.isCuratedForHostMode(contextGraphId);
6699
- if (!session.active || this.gossipSession !== session) {
6783
+ if (!requestIsCurrent()
6784
+ || session.swmHostModeHandlers.get(hostKey) !== handler
6785
+ || session.swmHostModeSubscribed.get(hostKey) !== source) {
6786
+ return { subscribed: false, alreadySubscribed: false, hostingEnabled: true };
6787
+ }
6788
+ const strip = this.swmHostModeStripCiphertext();
6789
+ const publicPolicy = this.isExactPublicManualSwmHostMode(contextGraphId, hostKey);
6790
+ const ownsHandler = handler !== undefined && wireOwner === localId;
6791
+ // Absence of private evidence is not public proof. Close only this owner's
6792
+ // existing dispatch; retain its operator provenance and durable marker.
6793
+ if (strip && !publicPolicy) {
6794
+ if (ownsHandler)
6795
+ session.swmHostModeCurated.set(hostKey, true);
6796
+ this.log.info(createOperationContext('system'), `SWM host-mode subscribe REFUSED for "${contextGraphId}": private-ciphertext strip requires exact public access policy`);
6797
+ return { subscribed: false, alreadySubscribed: false, hostingEnabled: true };
6798
+ }
6799
+ if (strip && (handler !== undefined || source !== undefined) && !ownsHandler) {
6700
6800
  return { subscribed: false, alreadySubscribed: false, hostingEnabled: true };
6701
6801
  }
6702
6802
  if (this.swmHostModeSubscribed.has(hostKey)) {
@@ -6713,31 +6813,27 @@ export class SwmHostModeMethods extends DKGAgentBase {
6713
6813
  // this canonicalisation the second subscribe would wire a
6714
6814
  // duplicate gossip handler on the same topic and double every
6715
6815
  // host-mode ingest/persistence.
6716
- // Never downgrade a positive classification on a transient policy-read
6717
- // failure. A false -> true transition closes both dispatch branches.
6718
- this.swmHostModeCurated.set(hostKey, this.swmHostModeCurated.get(hostKey) === true || curated);
6816
+ // Exact public policy can reopen this owner after an unknown-policy
6817
+ // refusal. Strip-off re-entry retains positive private classification.
6818
+ this.swmHostModeCurated.set(hostKey, strip && ownsHandler && source === SUBSCRIPTION_SOURCES.MANUAL
6819
+ ? false : this.swmHostModeCurated.get(hostKey) === true || curated);
6719
6820
  await this.maybeMarkRegisteredForHostMode(contextGraphId);
6821
+ if (!requestIsCurrent() || session.swmHostModeHandlers.get(hostKey) !== handler
6822
+ || session.swmHostModeSubscribed.get(hostKey) !== source
6823
+ || (strip && !this.isExactPublicManualSwmHostMode(contextGraphId, hostKey))) {
6824
+ return { subscribed: false, alreadySubscribed: false, hostingEnabled: true };
6825
+ }
6720
6826
  return { subscribed: false, alreadySubscribed: true, hostingEnabled: true };
6721
6827
  }
6722
- // OT-RFC-49 WS-A — CLOSE the operator hatch. With the private-ciphertext
6723
- // strip ON (default), the operator override must NOT re-introduce private
6724
- // custody for a CURATED CG: WS-A diverges from rung-1 (which deliberately
6725
- // left this manual path open) precisely here — there is no supported way
6726
- // back into private host-mode for a curated CG while the strip is on.
6727
- // Scoped to curated CGs via the SAME three-source probe the auto-host
6728
- // path uses ({@link isCuratedForHostMode}), NOT `isPrivateContextGraph`
6729
- // alone — a host-only core has no local `_meta`, so an
6730
- // `isPrivateContextGraph`-only check would return false and leave the
6731
- // hatch open for exactly the case WS-A closes. PUBLIC / bare-uncurated CGs
6732
- // are never affected (all three sources return not-curated → hatch stays
6733
- // open).
6734
- if (this.swmHostModeStripCiphertext() && curated) {
6735
- this.log.info(createOperationContext('system'), `SWM host-mode subscribe REFUSED for "${contextGraphId}": private-ciphertext strip is ON ` +
6736
- `(OT-RFC-49 WS-A — the operator override is closed for curated CGs; cores custody zero private SWM ciphertext)`);
6737
- return { subscribed: false, alreadySubscribed: false, hostingEnabled: true };
6738
- }
6739
- this.wireSwmHostModeHandler(contextGraphId, SUBSCRIPTION_SOURCES.MANUAL, curated);
6828
+ this.wireSwmHostModeHandler(contextGraphId, SUBSCRIPTION_SOURCES.MANUAL, strip ? false : curated);
6829
+ const createdHandler = session.swmHostModeHandlers.get(hostKey);
6830
+ const createdIsCurrent = () => requestIsCurrent() && createdHandler !== undefined
6831
+ && session.swmHostModeHandlers.get(hostKey) === createdHandler
6832
+ && session.swmHostModeSubscribed.get(hostKey) === SUBSCRIPTION_SOURCES.MANUAL
6833
+ && (!strip || this.isExactPublicManualSwmHostMode(contextGraphId, hostKey));
6740
6834
  await this.awaitHostModePersistence(contextGraphId);
6835
+ if (!createdIsCurrent())
6836
+ return { subscribed: false, alreadySubscribed: false, hostingEnabled: true };
6741
6837
  // Codex PR #610 R1 comment 5: a core that only knows the CG by
6742
6838
  // topic id (the explicit /host-mode/subscribe entrypoint) must
6743
6839
  // still transition the store to the registered-CG limits as
@@ -6746,6 +6842,8 @@ export class SwmHostModeMethods extends DKGAgentBase {
6746
6842
  // forever and prune ciphertext from registered CGs much
6747
6843
  // earlier than intended.
6748
6844
  await this.maybeMarkRegisteredForHostMode(contextGraphId);
6845
+ if (!createdIsCurrent())
6846
+ return { subscribed: false, alreadySubscribed: false, hostingEnabled: true };
6749
6847
  this.log.info(createOperationContext('system'), `SWM host-mode subscription explicitly enabled for "${contextGraphId}" via API (role=${this.config.nodeRole ?? 'edge'})`);
6750
6848
  return { subscribed: true, alreadySubscribed: false, hostingEnabled: true };
6751
6849
  }