@semiont/make-meaning 0.5.29 → 0.5.30

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.
@@ -1,12 +1,12 @@
1
1
  import { HttpTransport } from '@semiont/http-transport';
2
- import { accessToken, EventBus, baseUrl as baseUrl$1, errField, PERSISTED_EVENT_TYPES, retryWithBackoff, isTransientFetchError, STARTUP_FETCH_RETRY, userId, resourceId, generateUuid, annotationId, getBodySource, getTargetSource, getTargetSelector, getExactText, getStorageUri, cloneToken, getResourceEntityTypes, didToAgent, assembleAnnotation, busRequest, BUS_OPERATIONS, getPrimaryRepresentation, decodeRepresentation, getResourceId, deriveViews, getTextPositionSelector, isAnnotatable, softwareToAgent } from '@semiont/core';
2
+ import { replyChannelsFor, accessToken, EventBus, baseUrl as baseUrl$1, errField, PERSISTED_EVENT_TYPES, retryWithBackoff, isTransientFetchError, STARTUP_FETCH_RETRY, userId, resourceId, generateUuid, annotationId, getBodySource, getTargetSource, getTargetSelector, getExactText, getStorageUri, cloneToken, getResourceEntityTypes, didToAgent, assembleAnnotation, busRequest, getPrimaryRepresentation, decodeRepresentation, getResourceId, deriveViews, getTextPositionSelector, isAnnotatable, softwareToAgent } from '@semiont/core';
3
3
  import { loadEnvironmentConfig, SemiontProject } from '@semiont/core/node';
4
4
  import { createEventStore, resolveStorageUri, EventQuery } from '@semiont/event-sourcing';
5
5
  import { WorkingTreeStore, createAnchoredTextStore, RepresentationMissing, ChecksumMismatchError } from '@semiont/content';
6
6
  import { getGraphDatabase, compareByRecencyThenId } from '@semiont/graph';
7
7
  import { createEmbeddingProvider, createVectorStore, mergeByResource } from '@semiont/vectors';
8
8
  import { promises } from 'fs';
9
- import { withActorSpan, recordGatherDegrade } from '@semiont/observability';
9
+ import { registerFactPumpDepthProvider, withActorSpan, recordGatherDegrade } from '@semiont/observability';
10
10
  import * as path3 from 'path';
11
11
  import { DEFAULT_ENTITY_TYPES, getEntityTypes } from '@semiont/ontology';
12
12
  import { createInferenceClient } from '@semiont/inference';
@@ -7804,7 +7804,7 @@ var require_tap = __commonJS({
7804
7804
  var lift_1 = require_lift();
7805
7805
  var OperatorSubscriber_1 = require_OperatorSubscriber();
7806
7806
  var identity_1 = require_identity();
7807
- function tap(observerOrNext, error, complete) {
7807
+ function tap2(observerOrNext, error, complete) {
7808
7808
  var tapObserver = isFunction_1.isFunction(observerOrNext) || error || complete ? { next: observerOrNext, error, complete } : observerOrNext;
7809
7809
  return tapObserver ? lift_1.operate(function(source, subscriber) {
7810
7810
  var _a;
@@ -7833,7 +7833,7 @@ var require_tap = __commonJS({
7833
7833
  }));
7834
7834
  }) : identity_1.identity;
7835
7835
  }
7836
- exports.tap = tap;
7836
+ exports.tap = tap2;
7837
7837
  }
7838
7838
  });
7839
7839
 
@@ -9727,8 +9727,7 @@ var require_operators = __commonJS({
9727
9727
  });
9728
9728
 
9729
9729
  // src/archivist-main.ts
9730
- var import_rxjs5 = __toESM(require_cjs());
9731
- var import_operators4 = __toESM(require_operators());
9730
+ var import_rxjs6 = __toESM(require_cjs());
9732
9731
 
9733
9732
  // src/stower.ts
9734
9733
  var import_rxjs = __toESM(require_cjs());
@@ -9772,6 +9771,7 @@ var STOWER_CHANNELS = [
9772
9771
  "yield:update",
9773
9772
  "yield:mv",
9774
9773
  "mark:create",
9774
+ "mark:commit",
9775
9775
  "mark:delete",
9776
9776
  "mark:update-body",
9777
9777
  "frame:add-entity-type",
@@ -9808,6 +9808,7 @@ var Stower = class {
9808
9808
  pipe("yield:update", (e) => this.handleYieldUpdate(e)),
9809
9809
  pipe("yield:mv", (e) => this.handleYieldMv(e)),
9810
9810
  pipe("mark:create", (e) => this.handleMarkCreate(e)),
9811
+ pipe("mark:commit", (e) => this.handleMarkCommit(e)),
9811
9812
  pipe("mark:delete", (e) => this.handleMarkDelete(e)),
9812
9813
  pipe("mark:update-body", (e) => this.handleMarkUpdateBody(e)),
9813
9814
  pipe("frame:add-entity-type", (e) => this.handleAddEntityType(e)),
@@ -10033,6 +10034,61 @@ var Stower = class {
10033
10034
  });
10034
10035
  }
10035
10036
  }
10037
+ /**
10038
+ * Persist a detection unit's annotations as ONE acknowledged batch, then
10039
+ * answer (JOB-RESTART-SAFETY P6).
10040
+ *
10041
+ * The difference from `mark:create` is the reply, and it is the whole point.
10042
+ * `mark:create` is fire-and-forget: the worker's emit resolves when the bus
10043
+ * accepts it, which says nothing about the event log, so a down Stower loses
10044
+ * a unit silently and a flapping one hangs the worker forever. This answers
10045
+ * only after every append has returned, so the worker can gate unit
10046
+ * completion — and its checkpoint — on durability.
10047
+ *
10048
+ * Appends are sequential, not concurrent: the event log is the system of
10049
+ * record and a batch that half-lands under concurrency is harder to reason
10050
+ * about than one that stops at the first failure. A partial batch is
10051
+ * reported as a failure and the worker retries the WHOLE unit, which is safe
10052
+ * because ids are deterministic (P3) and the annotation fold is idempotent
10053
+ * by id — re-appending what already landed changes nothing.
10054
+ */
10055
+ async handleMarkCommit(event) {
10056
+ if (!event._userId) {
10057
+ throw new Error("mark:commit missing _userId (gateway injection)");
10058
+ }
10059
+ const annotations = event.annotations ?? [];
10060
+ try {
10061
+ let persisted = 0;
10062
+ for (const annotation of annotations) {
10063
+ await this.stores.eventStore.appendEvent({
10064
+ type: "mark:added",
10065
+ resourceId: resourceId(event.resourceId),
10066
+ userId: userId(event._userId),
10067
+ version: 1,
10068
+ payload: { annotation }
10069
+ });
10070
+ persisted++;
10071
+ }
10072
+ this.logger.debug("Committed annotation batch", {
10073
+ correlationId: event.correlationId,
10074
+ resourceId: event.resourceId,
10075
+ persisted
10076
+ });
10077
+ this.eventBus.get("mark:commit-ok").next({
10078
+ correlationId: event.correlationId,
10079
+ response: { persisted, annotationIds: annotations.map((a) => String(a.id)) }
10080
+ });
10081
+ } catch (error) {
10082
+ this.logger.error("Failed to commit annotation batch", {
10083
+ correlationId: event.correlationId,
10084
+ error: errField(error)
10085
+ });
10086
+ this.eventBus.get("mark:commit-failed").next({
10087
+ correlationId: event.correlationId,
10088
+ message: error instanceof Error ? error.message : String(error)
10089
+ });
10090
+ }
10091
+ }
10036
10092
  async handleMarkDelete(event) {
10037
10093
  if (!event._userId) {
10038
10094
  throw new Error("mark:delete missing _userId (gateway injection)");
@@ -10280,8 +10336,8 @@ var import_operators2 = __toESM(require_operators());
10280
10336
 
10281
10337
  // src/smelt-progress.ts
10282
10338
  var SmeltProgressTimeout = class extends Error {
10283
- constructor(resourceId6, contentChecksum, timeoutMs) {
10284
- super(`smelt:settled not observed for ${resourceId6} (checksum ${contentChecksum.slice(0, 12)}\u2026) within ${timeoutMs}ms`);
10339
+ constructor(resourceId8, contentChecksum, timeoutMs) {
10340
+ super(`smelt:settled not observed for ${resourceId8} (checksum ${contentChecksum.slice(0, 12)}\u2026) within ${timeoutMs}ms`);
10285
10341
  this.name = "SmeltProgressTimeout";
10286
10342
  }
10287
10343
  };
@@ -10292,7 +10348,7 @@ function createSmeltProgress(eventBus) {
10292
10348
  const waiters = /* @__PURE__ */ new Set();
10293
10349
  let disposed = false;
10294
10350
  let lastSweep = Date.now();
10295
- const subscription = eventBus.get("smelt:settled").subscribe(({ resourceId: resourceId6, contentChecksum, outcome }) => {
10351
+ const subscription = eventBus.get("smelt:settled").subscribe(({ resourceId: resourceId8, contentChecksum, outcome }) => {
10296
10352
  const now = Date.now();
10297
10353
  if (now - lastSweep >= SWEEP_INTERVAL_MS) {
10298
10354
  lastSweep = now;
@@ -10300,9 +10356,9 @@ function createSmeltProgress(eventBus) {
10300
10356
  if (now - entry.at >= SETTLED_TTL_MS) settled.delete(rid);
10301
10357
  }
10302
10358
  }
10303
- settled.set(resourceId6, { contentChecksum, outcome, at: now });
10359
+ settled.set(resourceId8, { contentChecksum, outcome, at: now });
10304
10360
  for (const waiter of waiters) {
10305
- if (waiter.resourceId === resourceId6 && waiter.contentChecksum === contentChecksum) {
10361
+ if (waiter.resourceId === resourceId8 && waiter.contentChecksum === contentChecksum) {
10306
10362
  clearTimeout(waiter.timer);
10307
10363
  waiters.delete(waiter);
10308
10364
  waiter.resolve(outcome);
@@ -10310,24 +10366,24 @@ function createSmeltProgress(eventBus) {
10310
10366
  }
10311
10367
  });
10312
10368
  return {
10313
- settledAt: (resourceId6) => {
10314
- const entry = settled.get(resourceId6);
10369
+ settledAt: (resourceId8) => {
10370
+ const entry = settled.get(resourceId8);
10315
10371
  return entry ? { contentChecksum: entry.contentChecksum, outcome: entry.outcome } : void 0;
10316
10372
  },
10317
- whenSettled: (resourceId6, contentChecksum, timeoutMs) => {
10373
+ whenSettled: (resourceId8, contentChecksum, timeoutMs) => {
10318
10374
  if (disposed) return Promise.resolve("inert");
10319
- const current = settled.get(resourceId6);
10375
+ const current = settled.get(resourceId8);
10320
10376
  if (current && current.contentChecksum === contentChecksum) {
10321
10377
  return Promise.resolve(current.outcome);
10322
10378
  }
10323
10379
  return new Promise((resolve2, reject) => {
10324
10380
  const waiter = {
10325
- resourceId: resourceId6,
10381
+ resourceId: resourceId8,
10326
10382
  contentChecksum,
10327
10383
  resolve: resolve2,
10328
10384
  timer: setTimeout(() => {
10329
10385
  waiters.delete(waiter);
10330
- reject(new SmeltProgressTimeout(resourceId6, contentChecksum, timeoutMs));
10386
+ reject(new SmeltProgressTimeout(resourceId8, contentChecksum, timeoutMs));
10331
10387
  }, timeoutMs)
10332
10388
  };
10333
10389
  waiters.add(waiter);
@@ -10349,14 +10405,14 @@ function createSmeltProgress(eventBus) {
10349
10405
 
10350
10406
  // src/read-anchored-text.ts
10351
10407
  var ANCHORED_TEXT_SETTLE_TIMEOUT_MS = 15e3;
10352
- async function readAnchoredText(kb, resourceId6) {
10353
- const view = await kb.views.get(resourceId(resourceId6));
10408
+ async function readAnchoredText(kb, resourceId8) {
10409
+ const view = await kb.views.get(resourceId(resourceId8));
10354
10410
  const checksum = getPrimaryRepresentation(view?.resource)?.checksum;
10355
10411
  if (!checksum) return null;
10356
10412
  const hit = await kb.anchoredText.read(checksum);
10357
10413
  if (hit) return hit;
10358
10414
  try {
10359
- const outcome = await kb.smeltProgress.whenSettled(resourceId6, checksum, ANCHORED_TEXT_SETTLE_TIMEOUT_MS);
10415
+ const outcome = await kb.smeltProgress.whenSettled(resourceId8, checksum, ANCHORED_TEXT_SETTLE_TIMEOUT_MS);
10360
10416
  return outcome === "indexed" ? kb.anchoredText.read(checksum) : null;
10361
10417
  } catch (error) {
10362
10418
  if (error instanceof SmeltProgressTimeout) return null;
@@ -10411,11 +10467,11 @@ function representationSource(resource) {
10411
10467
  mediaType: primary.mediaType
10412
10468
  };
10413
10469
  }
10414
- async function resolveRepresentation(deps, resourceId6) {
10415
- const view = await deps.views.get(resourceId6);
10416
- if (!view?.resource) throw new RepresentationMissing(String(resourceId6), "resource");
10470
+ async function resolveRepresentation(deps, resourceId8) {
10471
+ const view = await deps.views.get(resourceId8);
10472
+ if (!view?.resource) throw new RepresentationMissing(String(resourceId8), "resource");
10417
10473
  const source = representationSource(view.resource);
10418
- if (!source) throw new RepresentationMissing(String(resourceId6), "representation");
10474
+ if (!source) throw new RepresentationMissing(String(resourceId8), "representation");
10419
10475
  return { stream: deps.content.retrieveStream(source.storageUri), mediaType: source.mediaType };
10420
10476
  }
10421
10477
  var SEMANTIC_OVER_FETCH = 4;
@@ -10423,8 +10479,8 @@ var ResourceContext = class _ResourceContext {
10423
10479
  /**
10424
10480
  * Get resource metadata from view storage
10425
10481
  */
10426
- static async getResourceMetadata(resourceId6, kb) {
10427
- const view = await kb.views.get(resourceId6);
10482
+ static async getResourceMetadata(resourceId8, kb) {
10483
+ const view = await kb.views.get(resourceId8);
10428
10484
  if (!view) {
10429
10485
  return null;
10430
10486
  }
@@ -10547,8 +10603,8 @@ var ResourceContext = class _ResourceContext {
10547
10603
 
10548
10604
  // src/weave-progress.ts
10549
10605
  var WeaveProgressTimeout = class extends Error {
10550
- constructor(resourceId6, sequenceNumber, timeoutMs) {
10551
- super(`weave:applied parity not reached for ${resourceId6} (seq ${sequenceNumber}) within ${timeoutMs}ms`);
10606
+ constructor(resourceId8, sequenceNumber, timeoutMs) {
10607
+ super(`weave:applied parity not reached for ${resourceId8} (seq ${sequenceNumber}) within ${timeoutMs}ms`);
10552
10608
  this.name = "WeaveProgressTimeout";
10553
10609
  }
10554
10610
  };
@@ -10572,19 +10628,19 @@ var GraphContext = class {
10572
10628
  * - annotations on the resource → `annotation` nodes + `annotation-of` edges,
10573
10629
  * so siblingEntityTypes = union of those nodes' entityTypes
10574
10630
  */
10575
- static async buildKnowledgeGraph(resourceId6, kb, logger2) {
10576
- let mainDoc = await kb.graph.getResource(resourceId6);
10631
+ static async buildKnowledgeGraph(resourceId8, kb, logger2) {
10632
+ let mainDoc = await kb.graph.getResource(resourceId8);
10577
10633
  if (!mainDoc) {
10578
- const view = await kb.views.get(resourceId6);
10634
+ const view = await kb.views.get(resourceId8);
10579
10635
  if (view) {
10580
10636
  if (view.lastSequence !== void 0) {
10581
10637
  try {
10582
10638
  await kb.weaveProgress.whenApplied(
10583
- String(resourceId6),
10639
+ String(resourceId8),
10584
10640
  view.lastSequence,
10585
10641
  PROJECTION_BARRIER_TIMEOUT_MS
10586
10642
  );
10587
- mainDoc = await kb.graph.getResource(resourceId6);
10643
+ mainDoc = await kb.graph.getResource(resourceId8);
10588
10644
  } catch (error) {
10589
10645
  if (!(error instanceof WeaveProgressTimeout)) throw error;
10590
10646
  }
@@ -10592,19 +10648,19 @@ var GraphContext = class {
10592
10648
  if (!mainDoc) {
10593
10649
  for (const delayMs of PROJECTION_LAG_BACKOFF_MS) {
10594
10650
  await new Promise((resolve2) => setTimeout(resolve2, delayMs));
10595
- mainDoc = await kb.graph.getResource(resourceId6);
10651
+ mainDoc = await kb.graph.getResource(resourceId8);
10596
10652
  if (mainDoc) break;
10597
10653
  }
10598
10654
  }
10599
10655
  if (!mainDoc) {
10600
10656
  recordGatherDegrade("graph");
10601
10657
  logger2?.warn("[gather DEGRADED] graph projection did not catch up \u2014 resource present in views, absent in graph", {
10602
- resourceId: String(resourceId6),
10658
+ resourceId: String(resourceId8),
10603
10659
  lastSequence: view.lastSequence,
10604
10660
  barrierTimeoutMs: PROJECTION_BARRIER_TIMEOUT_MS
10605
10661
  });
10606
10662
  throw new Error(
10607
- `Graph projection did not catch up for ${String(resourceId6)} \u2014 present in views, absent in graph (Weaver lag, not a missing resource)`
10663
+ `Graph projection did not catch up for ${String(resourceId8)} \u2014 present in views, absent in graph (Weaver lag, not a missing resource)`
10608
10664
  );
10609
10665
  }
10610
10666
  }
@@ -10612,11 +10668,11 @@ var GraphContext = class {
10612
10668
  if (!mainDoc) {
10613
10669
  throw new Error("Resource not found");
10614
10670
  }
10615
- const mainId = String(resourceId6);
10671
+ const mainId = String(resourceId8);
10616
10672
  const [connections, referencedBy, annotations] = await Promise.all([
10617
- kb.graph.getResourceConnections(resourceId6),
10618
- kb.graph.getResourceReferencedBy(resourceId6),
10619
- kb.graph.getResourceAnnotations(resourceId6)
10673
+ kb.graph.getResourceConnections(resourceId8),
10674
+ kb.graph.getResourceReferencedBy(resourceId8),
10675
+ kb.graph.getResourceAnnotations(resourceId8)
10620
10676
  ]);
10621
10677
  const nodes = [];
10622
10678
  const edges = [];
@@ -10636,7 +10692,7 @@ var GraphContext = class {
10636
10692
  const citedSeen = /* @__PURE__ */ new Set();
10637
10693
  for (const ann of referencedBy) {
10638
10694
  const source = getTargetSource(ann.target);
10639
- if (!source || source === String(resourceId6) || !ann.id || seen.has(ann.id)) continue;
10695
+ if (!source || source === String(resourceId8) || !ann.id || seen.has(ann.id)) continue;
10640
10696
  if (!citedSeen.has(source)) {
10641
10697
  citedSeen.add(source);
10642
10698
  const view = await kb.views.get(resourceId(source));
@@ -10670,7 +10726,7 @@ var AnnotationContext = class {
10670
10726
  * @returns Rich context for LLM processing
10671
10727
  * @throws Error if annotation or resource not found
10672
10728
  */
10673
- static async buildLLMContext(annotationId4, resourceId6, kb, embeddingProvider, options = {}, inferenceClient, logger2) {
10729
+ static async buildLLMContext(annotationId4, resourceId8, kb, embeddingProvider, options = {}, inferenceClient, logger2) {
10674
10730
  const {
10675
10731
  includeSourceContext = true,
10676
10732
  includeTargetContext = true,
@@ -10679,22 +10735,22 @@ var AnnotationContext = class {
10679
10735
  if (contextWindow < 100 || contextWindow > 5e3) {
10680
10736
  throw new Error("contextWindow must be between 100 and 5000");
10681
10737
  }
10682
- logger2?.debug("Building LLM context", { annotationId: annotationId4, resourceId: resourceId6 });
10683
- logger2?.debug("Getting view for resource", { resourceId: resourceId6 });
10738
+ logger2?.debug("Building LLM context", { annotationId: annotationId4, resourceId: resourceId8 });
10739
+ logger2?.debug("Getting view for resource", { resourceId: resourceId8 });
10684
10740
  let sourceView;
10685
10741
  try {
10686
- sourceView = await kb.views.get(resourceId6);
10742
+ sourceView = await kb.views.get(resourceId8);
10687
10743
  logger2?.debug("Retrieved view", { hasView: !!sourceView });
10688
10744
  if (!sourceView) {
10689
10745
  throw new Error("Source resource not found");
10690
10746
  }
10691
10747
  } catch (error) {
10692
- logger2?.error("Error getting view", { resourceId: resourceId6, error });
10748
+ logger2?.error("Error getting view", { resourceId: resourceId8, error });
10693
10749
  throw error;
10694
10750
  }
10695
10751
  logger2?.debug("Looking for annotation in resource", {
10696
10752
  annotationId: annotationId4,
10697
- resourceId: resourceId6,
10753
+ resourceId: resourceId8,
10698
10754
  totalAnnotations: sourceView.annotations.annotations.length,
10699
10755
  firstFiveIds: sourceView.annotations.annotations.slice(0, 5).map((a) => a.id)
10700
10756
  });
@@ -10704,9 +10760,9 @@ var AnnotationContext = class {
10704
10760
  throw new Error("Annotation not found in view");
10705
10761
  }
10706
10762
  const targetSource = getTargetSource(annotation.target);
10707
- logger2?.debug("Validating target resource", { targetSource, expectedResourceId: resourceId6 });
10708
- if (targetSource !== String(resourceId6)) {
10709
- throw new Error(`Annotation target resource ID (${targetSource}) does not match expected resource ID (${resourceId6})`);
10763
+ logger2?.debug("Validating target resource", { targetSource, expectedResourceId: resourceId8 });
10764
+ if (targetSource !== String(resourceId8)) {
10765
+ throw new Error(`Annotation target resource ID (${targetSource}) does not match expected resource ID (${resourceId8})`);
10710
10766
  }
10711
10767
  const sourceDoc = sourceView.resource;
10712
10768
  const bodySource = getBodySource(annotation.body);
@@ -10722,7 +10778,7 @@ var AnnotationContext = class {
10722
10778
  throw new Error("Source content not found: no storageUri");
10723
10779
  }
10724
10780
  const primaryRep = getPrimaryRepresentation(sourceDoc);
10725
- const { data: sourceContent } = await kb.content.getBinary(resourceId6);
10781
+ const { data: sourceContent } = await kb.content.getBinary(resourceId8);
10726
10782
  const contentStr = decodeRepresentation(Buffer.from(sourceContent), primaryRep?.mediaType ?? "text/plain");
10727
10783
  const targetSelectorRaw = getTargetSelector(annotation.target);
10728
10784
  const targetSelector = Array.isArray(targetSelectorRaw) ? targetSelectorRaw[0] : targetSelectorRaw;
@@ -10769,9 +10825,9 @@ var AnnotationContext = class {
10769
10825
  };
10770
10826
  }
10771
10827
  }
10772
- logger2?.debug("Building knowledge graph", { resourceId: resourceId6 });
10773
- const graph = await GraphContext.buildKnowledgeGraph(resourceId6, kb, logger2);
10774
- const views = deriveViews(graph, String(resourceId6), annotationId4);
10828
+ logger2?.debug("Building knowledge graph", { resourceId: resourceId8 });
10829
+ const graph = await GraphContext.buildKnowledgeGraph(resourceId8, kb, logger2);
10830
+ const views = deriveViews(graph, String(resourceId8), annotationId4);
10775
10831
  const entityTypeStats = await kb.graph.getEntityTypeStats();
10776
10832
  const entityTypeFrequencies = {};
10777
10833
  for (const stat of entityTypeStats) {
@@ -10808,7 +10864,7 @@ Summary:`;
10808
10864
  const results = await kb.vectors.searchAnnotations(focalEmbedding, {
10809
10865
  limit: 10,
10810
10866
  scoreThreshold: 0.5,
10811
- filter: { excludeResourceId: resourceId6 }
10867
+ filter: { excludeResourceId: resourceId8 }
10812
10868
  });
10813
10869
  const similar = [];
10814
10870
  for (const r of results) {
@@ -10861,10 +10917,10 @@ Summary:`;
10861
10917
  * Get resource annotations from view storage (fast path)
10862
10918
  * Throws if view missing
10863
10919
  */
10864
- static async getResourceAnnotations(resourceId6, kb) {
10865
- const view = await kb.views.get(resourceId6);
10920
+ static async getResourceAnnotations(resourceId8, kb) {
10921
+ const view = await kb.views.get(resourceId8);
10866
10922
  if (!view) {
10867
- throw new Error(`Resource ${resourceId6} not found in view storage`);
10923
+ throw new Error(`Resource ${resourceId8} not found in view storage`);
10868
10924
  }
10869
10925
  return view.annotations;
10870
10926
  }
@@ -10872,8 +10928,8 @@ Summary:`;
10872
10928
  * Get all annotations
10873
10929
  * @returns Array of all annotation objects
10874
10930
  */
10875
- static async getAllAnnotations(resourceId6, kb) {
10876
- const annotations = await this.getResourceAnnotations(resourceId6, kb);
10931
+ static async getAllAnnotations(resourceId8, kb) {
10932
+ const annotations = await this.getResourceAnnotations(resourceId8, kb);
10877
10933
  return this.enrichResolvedReferences(annotations.annotations, kb);
10878
10934
  }
10879
10935
  /**
@@ -10942,8 +10998,8 @@ Summary:`;
10942
10998
  * Get resource stats (version info)
10943
10999
  * @returns Version and timestamp info for the annotations
10944
11000
  */
10945
- static async getResourceStats(resourceId6, kb) {
10946
- const annotations = await this.getResourceAnnotations(resourceId6, kb);
11001
+ static async getResourceStats(resourceId8, kb) {
11002
+ const annotations = await this.getResourceAnnotations(resourceId8, kb);
10947
11003
  return {
10948
11004
  resourceId: annotations.resourceId,
10949
11005
  version: annotations.version,
@@ -10953,15 +11009,15 @@ Summary:`;
10953
11009
  /**
10954
11010
  * Check if resource exists in view storage
10955
11011
  */
10956
- static async resourceExists(resourceId6, kb) {
10957
- return kb.views.exists(resourceId6);
11012
+ static async resourceExists(resourceId8, kb) {
11013
+ return kb.views.exists(resourceId8);
10958
11014
  }
10959
11015
  /**
10960
11016
  * Get a single annotation by ID
10961
11017
  * O(1) lookup using resource ID to access view storage
10962
11018
  */
10963
- static async getAnnotation(annotationId4, resourceId6, kb) {
10964
- const annotations = await this.getResourceAnnotations(resourceId6, kb);
11019
+ static async getAnnotation(annotationId4, resourceId8, kb) {
11020
+ const annotations = await this.getResourceAnnotations(resourceId8, kb);
10965
11021
  return annotations.annotations.find((a) => a.id === annotationId4) || null;
10966
11022
  }
10967
11023
  /**
@@ -10978,8 +11034,8 @@ Summary:`;
10978
11034
  /**
10979
11035
  * Get annotation context (selected text with surrounding context)
10980
11036
  */
10981
- static async getAnnotationContext(annotationId4, resourceId6, contextBefore, contextAfter, kb) {
10982
- const annotation = await this.getAnnotation(annotationId4, resourceId6, kb);
11037
+ static async getAnnotationContext(annotationId4, resourceId8, contextBefore, contextAfter, kb) {
11038
+ const annotation = await this.getAnnotation(annotationId4, resourceId8, kb);
10983
11039
  if (!annotation) {
10984
11040
  throw new Error("Annotation not found");
10985
11041
  }
@@ -11010,8 +11066,8 @@ Summary:`;
11010
11066
  /**
11011
11067
  * Generate AI summary of annotation in context
11012
11068
  */
11013
- static async generateAnnotationSummary(annotationId4, resourceId6, kb, inferenceClient) {
11014
- const annotation = await this.getAnnotation(annotationId4, resourceId6, kb);
11069
+ static async generateAnnotationSummary(annotationId4, resourceId8, kb, inferenceClient) {
11070
+ const annotation = await this.getAnnotation(annotationId4, resourceId8, kb);
11015
11071
  if (!annotation) {
11016
11072
  throw new Error("Annotation not found");
11017
11073
  }
@@ -11092,10 +11148,10 @@ Entity types: ${entityTypes.join(", ")}`;
11092
11148
  return inferenceClient.generateText(summaryPrompt, 500, 0.5);
11093
11149
  }
11094
11150
  };
11095
- async function assembleResourceGraph(kb, resourceId6) {
11151
+ async function assembleResourceGraph(kb, resourceId8) {
11096
11152
  const eventQuery = new EventQuery(kb.eventStore.log.storage);
11097
- const events = await eventQuery.getResourceEvents(resourceId6);
11098
- const stored = await kb.eventStore.views.materializer.materialize(events, resourceId6);
11153
+ const events = await eventQuery.getResourceEvents(resourceId8);
11154
+ const stored = await kb.eventStore.views.materializer.materialize(events, resourceId8);
11099
11155
  if (!stored) return null;
11100
11156
  const annotations = stored.annotations.annotations;
11101
11157
  const entityReferences = annotations.filter((a) => {
@@ -12014,6 +12070,56 @@ var CloneTokenManager = class {
12014
12070
  this.logger.info("CloneTokenManager actor stopped");
12015
12071
  }
12016
12072
  };
12073
+ var MATCHER_CHANNELS = [
12074
+ "match:search-requested"
12075
+ ];
12076
+
12077
+ // src/gatherer.ts
12078
+ var GATHERER_CHANNELS = [
12079
+ "gather:requested",
12080
+ "gather:resource-requested"
12081
+ ];
12082
+
12083
+ // src/service-channels.ts
12084
+ var SMELTER_AWAITED_OPERATIONS = [
12085
+ "browse:resource-requested",
12086
+ "browse:annotations-requested",
12087
+ "browse:resources-requested"
12088
+ ];
12089
+ replyChannelsFor(SMELTER_AWAITED_OPERATIONS);
12090
+ var WEAVER_AWAITED_OPERATIONS = [
12091
+ "browse:resources-requested",
12092
+ "browse:events-requested",
12093
+ "browse:annotations-requested"
12094
+ ];
12095
+ replyChannelsFor(WEAVER_AWAITED_OPERATIONS);
12096
+ var LIBRARIAN_INBOUND_CHANNELS = [
12097
+ ...MATCHER_CHANNELS,
12098
+ ...GATHERER_CHANNELS,
12099
+ "gather:summary-requested",
12100
+ "weave:applied",
12101
+ "smelt:settled"
12102
+ ];
12103
+ replyChannelsFor(LIBRARIAN_INBOUND_CHANNELS);
12104
+ var ARCHIVIST_INBOUND_CHANNELS = [
12105
+ ...STOWER_CHANNELS,
12106
+ ...BROWSER_CHANNELS,
12107
+ ...CLONE_TOKEN_CHANNELS,
12108
+ "mark:create-request",
12109
+ "smelt:settled",
12110
+ // The annotation-context read moved here with the bytes (SINGLE-KB-MOUNT D5).
12111
+ "browse:annotation-context-requested"
12112
+ ];
12113
+ var ARCHIVIST_OUTBOUND_STRAYS = [
12114
+ "mark:body-update-failed",
12115
+ // op keyed 'bind:update-body' (gateway handler re-emits mark:update-body)
12116
+ "yield:move-failed"
12117
+ // yield:mv has no registered operation; failure is direct-subscribed
12118
+ ];
12119
+ var ARCHIVIST_OUTBOUND_CHANNELS = [
12120
+ ...ARCHIVIST_OUTBOUND_STRAYS,
12121
+ ...replyChannelsFor(ARCHIVIST_INBOUND_CHANNELS)
12122
+ ];
12017
12123
  var LIMITS_ENRICH_BUDGET_MS = 1500;
12018
12124
  function createLimitsDiscovery(config2, logger2, options) {
12019
12125
  const clientFactory = createInferenceClient;
@@ -12157,6 +12263,40 @@ function createArchivistServer(deps) {
12157
12263
  res.end();
12158
12264
  });
12159
12265
  }
12266
+
12267
+ // src/fact-pump.ts
12268
+ var import_rxjs5 = __toESM(require_cjs());
12269
+ function createFactPump(facts$, deps) {
12270
+ let depth = 0;
12271
+ const publish = async (event) => {
12272
+ try {
12273
+ const type = event.type;
12274
+ await Promise.all([
12275
+ deps.emit(type, event),
12276
+ ...event.resourceId ? [deps.emit(type, event, event.resourceId)] : []
12277
+ ]);
12278
+ } catch (error) {
12279
+ deps.logger.error("Fact publish failed \u2014 projectors will heal on their next catch-up", {
12280
+ type: event.type,
12281
+ resourceId: event.resourceId,
12282
+ sequenceNumber: event.metadata?.sequenceNumber,
12283
+ error: errField(error)
12284
+ });
12285
+ }
12286
+ };
12287
+ const subscription = facts$.pipe(
12288
+ (0, import_rxjs5.tap)(() => {
12289
+ depth += 1;
12290
+ }),
12291
+ (0, import_rxjs5.concatMap)((event) => (0, import_rxjs5.from)(publish(event).finally(() => {
12292
+ depth -= 1;
12293
+ })))
12294
+ ).subscribe();
12295
+ return {
12296
+ depth: () => depth,
12297
+ unsubscribe: () => subscription.unsubscribe()
12298
+ };
12299
+ }
12160
12300
  async function assertAnnotatableTarget(kb, target) {
12161
12301
  const view = await kb.views.get(resourceId(target));
12162
12302
  const mediaType = getPrimaryRepresentation(view?.resource)?.mediaType;
@@ -12255,8 +12395,8 @@ function registerAnnotationContextHandler(eventBus, kb, parentLogger) {
12255
12395
  }
12256
12396
  function workingTreeContentReads(views, content) {
12257
12397
  return {
12258
- getBinary: async (resourceId6) => {
12259
- const { stream, mediaType } = await resolveRepresentation({ views, content }, resourceId6);
12398
+ getBinary: async (resourceId8) => {
12399
+ const { stream, mediaType } = await resolveRepresentation({ views, content }, resourceId8);
12260
12400
  const chunks = [];
12261
12401
  for await (const chunk of stream) chunks.push(chunk);
12262
12402
  const buf = Buffer.concat(chunks);
@@ -12303,15 +12443,15 @@ function eventAnnotationId(event) {
12303
12443
  return null;
12304
12444
  }
12305
12445
  }
12306
- async function readAnnotationFromView(kb, resourceId6, annotationId4) {
12307
- const allAnnotations = await AnnotationContext.getAllAnnotations(resourceId6, kb);
12446
+ async function readAnnotationFromView(kb, resourceId8, annotationId4) {
12447
+ const allAnnotations = await AnnotationContext.getAllAnnotations(resourceId8, kb);
12308
12448
  return allAnnotations.find((a) => a.id === annotationId4) ?? null;
12309
12449
  }
12310
12450
  function wireEnrichment(eventStore, kb) {
12311
- eventStore.setEnrichEvent(async (event, resourceId6) => {
12451
+ eventStore.setEnrichEvent(async (event, resourceId8) => {
12312
12452
  const annId = eventAnnotationId(event);
12313
12453
  if (annId === null) return event;
12314
- const annotation = await readAnnotationFromView(kb, resourceId6, annId);
12454
+ const annotation = await readAnnotationFromView(kb, resourceId8, annId);
12315
12455
  if (annotation === null) return event;
12316
12456
  return { ...event, annotation };
12317
12457
  });
@@ -12346,34 +12486,8 @@ if (config.services.vectors.type === "memory") {
12346
12486
  }
12347
12487
  var workerSecret = process.env.SEMIONT_WORKER_SECRET ?? "";
12348
12488
  var skipRebuild = process.env.SEMIONT_SKIP_REBUILD === "true";
12349
- var healthPort = 9093;
12489
+ var healthPort = 24103;
12350
12490
  var logger = createProcessLogger("archivist");
12351
- var INBOUND_CHANNELS = [
12352
- ...STOWER_CHANNELS,
12353
- ...BROWSER_CHANNELS,
12354
- ...CLONE_TOKEN_CHANNELS,
12355
- "mark:create-request",
12356
- "smelt:settled",
12357
- // The annotation-context read moved here with the bytes (SINGLE-KB-MOUNT D5).
12358
- "browse:annotation-context-requested"
12359
- ];
12360
- var OUTBOUND_STRAYS = [
12361
- "mark:body-update-failed",
12362
- // op keyed 'bind:update-body' (gateway handler re-emits mark:update-body)
12363
- "yield:move-failed"
12364
- // yield:mv has no registered operation; failure is direct-subscribed
12365
- ];
12366
- function outboundChannels() {
12367
- const out = new Set(OUTBOUND_STRAYS);
12368
- for (const ch of INBOUND_CHANNELS) {
12369
- const op = BUS_OPERATIONS[ch];
12370
- if (!op) continue;
12371
- out.add(op.result);
12372
- out.add(op.failure);
12373
- if ("progress" in op && op.progress) out.add(op.progress);
12374
- }
12375
- return [...out];
12376
- }
12377
12491
  async function authenticate() {
12378
12492
  if (!workerSecret) {
12379
12493
  logger.warn("No SEMIONT_WORKER_SECRET set \u2014 using empty token");
@@ -12412,7 +12526,7 @@ async function main() {
12412
12526
  const { initObservabilityNode } = await import('@semiont/observability/node');
12413
12527
  initObservabilityNode({ serviceName: "semiont-archivist" });
12414
12528
  logger.info("Authenticating", { baseUrl });
12415
- const tokenSubject = new import_rxjs5.BehaviorSubject(accessToken(await authenticate()));
12529
+ const tokenSubject = new import_rxjs6.BehaviorSubject(accessToken(await authenticate()));
12416
12530
  logger.info("Authenticated");
12417
12531
  const refreshToken = async () => {
12418
12532
  const token = await authenticate();
@@ -12487,18 +12601,22 @@ async function main() {
12487
12601
  const httpTransport = new HttpTransport({
12488
12602
  baseUrl: baseUrl$1(baseUrl),
12489
12603
  token$: tokenSubject,
12490
- tokenRefresher: refreshToken
12604
+ tokenRefresher: refreshToken,
12605
+ // Exactly the inbound roster — never the full bridged set, whose global
12606
+ // reply fan-out is the worker-OOM failure mode. This process awaits no
12607
+ // wire replies (busRequest's isSubscribed gate fails fast if one is ever
12608
+ // added without growing the roster), so inbound IS the subscription.
12609
+ channels: ARCHIVIST_INBOUND_CHANNELS
12491
12610
  });
12492
12611
  const pumps = [];
12493
- httpTransport.actor.addChannels([...INBOUND_CHANNELS]);
12494
- for (const channel of INBOUND_CHANNELS) {
12612
+ for (const channel of ARCHIVIST_INBOUND_CHANNELS) {
12495
12613
  pumps.push(
12496
12614
  httpTransport.stream(channel).subscribe((payload) => {
12497
12615
  localBus.get(channel).next(payload);
12498
12616
  })
12499
12617
  );
12500
12618
  }
12501
- const outbound = outboundChannels();
12619
+ const outbound = ARCHIVIST_OUTBOUND_CHANNELS;
12502
12620
  for (const channel of outbound) {
12503
12621
  pumps.push(
12504
12622
  localBus.get(channel).subscribe((payload) => {
@@ -12508,26 +12626,13 @@ async function main() {
12508
12626
  })
12509
12627
  );
12510
12628
  }
12511
- const publishFact = async (event) => {
12512
- try {
12513
- const type = event.type;
12514
- await httpTransport.emit(type, event);
12515
- if (event.resourceId) {
12516
- await httpTransport.emit(type, event, event.resourceId);
12517
- }
12518
- } catch (error) {
12519
- logger.error("Fact publish failed \u2014 projectors will heal on their next catch-up", {
12520
- type: event.type,
12521
- resourceId: event.resourceId,
12522
- sequenceNumber: event.metadata?.sequenceNumber,
12523
- error: errField(error)
12524
- });
12525
- }
12526
- };
12527
- pumps.push(
12528
- (0, import_rxjs5.merge)(...PERSISTED_EVENT_TYPES.map((type) => localBus.getDomainEvent(type))).pipe((0, import_operators4.concatMap)((event) => (0, import_rxjs5.from)(publishFact(event)))).subscribe()
12629
+ const factPump = createFactPump(
12630
+ (0, import_rxjs6.merge)(...PERSISTED_EVENT_TYPES.map((type) => localBus.getDomainEvent(type))),
12631
+ { emit: (channel, payload, scope) => httpTransport.emit(channel, payload, scope), logger }
12529
12632
  );
12530
- logger.info("Bus pumps attached", { inbound: INBOUND_CHANNELS.length, outbound: outbound.length, facts: PERSISTED_EVENT_TYPES.length });
12633
+ pumps.push({ unsubscribe: () => factPump.unsubscribe() });
12634
+ registerFactPumpDepthProvider(() => factPump.depth());
12635
+ logger.info("Bus pumps attached", { inbound: ARCHIVIST_INBOUND_CHANNELS.length, outbound: outbound.length, facts: PERSISTED_EVENT_TYPES.length });
12531
12636
  const server = createArchivistServer({
12532
12637
  events: eventStore.log,
12533
12638
  content,
@@ -12558,7 +12663,7 @@ async function main() {
12558
12663
  };
12559
12664
  process.on("SIGTERM", shutdown);
12560
12665
  process.on("SIGINT", shutdown);
12561
- logger.info("Archivist serving", { channels: INBOUND_CHANNELS.length });
12666
+ logger.info("Archivist serving", { channels: ARCHIVIST_INBOUND_CHANNELS.length });
12562
12667
  }
12563
12668
  main().catch((error) => {
12564
12669
  logger.error("Fatal", { error: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : void 0 });