@semiont/make-meaning 0.5.29 → 0.5.31

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,17 +10405,19 @@ 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, settleTimeoutMs = ANCHORED_TEXT_SETTLE_TIMEOUT_MS) {
10409
+ const view = await kb.views.get(resourceId(resourceId8));
10354
10410
  const checksum = getPrimaryRepresentation(view?.resource)?.checksum;
10355
- if (!checksum) return null;
10411
+ if (!checksum) return { kind: "unknown" };
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);
10360
- return outcome === "indexed" ? kb.anchoredText.read(checksum) : null;
10415
+ const outcome = await kb.smeltProgress.whenSettled(resourceId8, checksum, settleTimeoutMs);
10416
+ if (outcome === "skipped") return { kind: "no-map" };
10417
+ if (outcome === "inert") return { kind: "not-yet" };
10418
+ return await kb.anchoredText.read(checksum) ?? { kind: "not-yet" };
10361
10419
  } catch (error) {
10362
- if (error instanceof SmeltProgressTimeout) return null;
10420
+ if (error instanceof SmeltProgressTimeout) return { kind: "not-yet" };
10363
10421
  throw error;
10364
10422
  }
10365
10423
  }
@@ -10411,11 +10469,11 @@ function representationSource(resource) {
10411
10469
  mediaType: primary.mediaType
10412
10470
  };
10413
10471
  }
10414
- async function resolveRepresentation(deps, resourceId6) {
10415
- const view = await deps.views.get(resourceId6);
10416
- if (!view?.resource) throw new RepresentationMissing(String(resourceId6), "resource");
10472
+ async function resolveRepresentation(deps, resourceId8) {
10473
+ const view = await deps.views.get(resourceId8);
10474
+ if (!view?.resource) throw new RepresentationMissing(String(resourceId8), "resource");
10417
10475
  const source = representationSource(view.resource);
10418
- if (!source) throw new RepresentationMissing(String(resourceId6), "representation");
10476
+ if (!source) throw new RepresentationMissing(String(resourceId8), "representation");
10419
10477
  return { stream: deps.content.retrieveStream(source.storageUri), mediaType: source.mediaType };
10420
10478
  }
10421
10479
  var SEMANTIC_OVER_FETCH = 4;
@@ -10423,8 +10481,8 @@ var ResourceContext = class _ResourceContext {
10423
10481
  /**
10424
10482
  * Get resource metadata from view storage
10425
10483
  */
10426
- static async getResourceMetadata(resourceId6, kb) {
10427
- const view = await kb.views.get(resourceId6);
10484
+ static async getResourceMetadata(resourceId8, kb) {
10485
+ const view = await kb.views.get(resourceId8);
10428
10486
  if (!view) {
10429
10487
  return null;
10430
10488
  }
@@ -10547,8 +10605,8 @@ var ResourceContext = class _ResourceContext {
10547
10605
 
10548
10606
  // src/weave-progress.ts
10549
10607
  var WeaveProgressTimeout = class extends Error {
10550
- constructor(resourceId6, sequenceNumber, timeoutMs) {
10551
- super(`weave:applied parity not reached for ${resourceId6} (seq ${sequenceNumber}) within ${timeoutMs}ms`);
10608
+ constructor(resourceId8, sequenceNumber, timeoutMs) {
10609
+ super(`weave:applied parity not reached for ${resourceId8} (seq ${sequenceNumber}) within ${timeoutMs}ms`);
10552
10610
  this.name = "WeaveProgressTimeout";
10553
10611
  }
10554
10612
  };
@@ -10572,19 +10630,19 @@ var GraphContext = class {
10572
10630
  * - annotations on the resource → `annotation` nodes + `annotation-of` edges,
10573
10631
  * so siblingEntityTypes = union of those nodes' entityTypes
10574
10632
  */
10575
- static async buildKnowledgeGraph(resourceId6, kb, logger2) {
10576
- let mainDoc = await kb.graph.getResource(resourceId6);
10633
+ static async buildKnowledgeGraph(resourceId8, kb, logger2) {
10634
+ let mainDoc = await kb.graph.getResource(resourceId8);
10577
10635
  if (!mainDoc) {
10578
- const view = await kb.views.get(resourceId6);
10636
+ const view = await kb.views.get(resourceId8);
10579
10637
  if (view) {
10580
10638
  if (view.lastSequence !== void 0) {
10581
10639
  try {
10582
10640
  await kb.weaveProgress.whenApplied(
10583
- String(resourceId6),
10641
+ String(resourceId8),
10584
10642
  view.lastSequence,
10585
10643
  PROJECTION_BARRIER_TIMEOUT_MS
10586
10644
  );
10587
- mainDoc = await kb.graph.getResource(resourceId6);
10645
+ mainDoc = await kb.graph.getResource(resourceId8);
10588
10646
  } catch (error) {
10589
10647
  if (!(error instanceof WeaveProgressTimeout)) throw error;
10590
10648
  }
@@ -10592,19 +10650,19 @@ var GraphContext = class {
10592
10650
  if (!mainDoc) {
10593
10651
  for (const delayMs of PROJECTION_LAG_BACKOFF_MS) {
10594
10652
  await new Promise((resolve2) => setTimeout(resolve2, delayMs));
10595
- mainDoc = await kb.graph.getResource(resourceId6);
10653
+ mainDoc = await kb.graph.getResource(resourceId8);
10596
10654
  if (mainDoc) break;
10597
10655
  }
10598
10656
  }
10599
10657
  if (!mainDoc) {
10600
10658
  recordGatherDegrade("graph");
10601
10659
  logger2?.warn("[gather DEGRADED] graph projection did not catch up \u2014 resource present in views, absent in graph", {
10602
- resourceId: String(resourceId6),
10660
+ resourceId: String(resourceId8),
10603
10661
  lastSequence: view.lastSequence,
10604
10662
  barrierTimeoutMs: PROJECTION_BARRIER_TIMEOUT_MS
10605
10663
  });
10606
10664
  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)`
10665
+ `Graph projection did not catch up for ${String(resourceId8)} \u2014 present in views, absent in graph (Weaver lag, not a missing resource)`
10608
10666
  );
10609
10667
  }
10610
10668
  }
@@ -10612,11 +10670,11 @@ var GraphContext = class {
10612
10670
  if (!mainDoc) {
10613
10671
  throw new Error("Resource not found");
10614
10672
  }
10615
- const mainId = String(resourceId6);
10673
+ const mainId = String(resourceId8);
10616
10674
  const [connections, referencedBy, annotations] = await Promise.all([
10617
- kb.graph.getResourceConnections(resourceId6),
10618
- kb.graph.getResourceReferencedBy(resourceId6),
10619
- kb.graph.getResourceAnnotations(resourceId6)
10675
+ kb.graph.getResourceConnections(resourceId8),
10676
+ kb.graph.getResourceReferencedBy(resourceId8),
10677
+ kb.graph.getResourceAnnotations(resourceId8)
10620
10678
  ]);
10621
10679
  const nodes = [];
10622
10680
  const edges = [];
@@ -10636,7 +10694,7 @@ var GraphContext = class {
10636
10694
  const citedSeen = /* @__PURE__ */ new Set();
10637
10695
  for (const ann of referencedBy) {
10638
10696
  const source = getTargetSource(ann.target);
10639
- if (!source || source === String(resourceId6) || !ann.id || seen.has(ann.id)) continue;
10697
+ if (!source || source === String(resourceId8) || !ann.id || seen.has(ann.id)) continue;
10640
10698
  if (!citedSeen.has(source)) {
10641
10699
  citedSeen.add(source);
10642
10700
  const view = await kb.views.get(resourceId(source));
@@ -10670,7 +10728,7 @@ var AnnotationContext = class {
10670
10728
  * @returns Rich context for LLM processing
10671
10729
  * @throws Error if annotation or resource not found
10672
10730
  */
10673
- static async buildLLMContext(annotationId4, resourceId6, kb, embeddingProvider, options = {}, inferenceClient, logger2) {
10731
+ static async buildLLMContext(annotationId4, resourceId8, kb, embeddingProvider, options = {}, inferenceClient, logger2) {
10674
10732
  const {
10675
10733
  includeSourceContext = true,
10676
10734
  includeTargetContext = true,
@@ -10679,22 +10737,22 @@ var AnnotationContext = class {
10679
10737
  if (contextWindow < 100 || contextWindow > 5e3) {
10680
10738
  throw new Error("contextWindow must be between 100 and 5000");
10681
10739
  }
10682
- logger2?.debug("Building LLM context", { annotationId: annotationId4, resourceId: resourceId6 });
10683
- logger2?.debug("Getting view for resource", { resourceId: resourceId6 });
10740
+ logger2?.debug("Building LLM context", { annotationId: annotationId4, resourceId: resourceId8 });
10741
+ logger2?.debug("Getting view for resource", { resourceId: resourceId8 });
10684
10742
  let sourceView;
10685
10743
  try {
10686
- sourceView = await kb.views.get(resourceId6);
10744
+ sourceView = await kb.views.get(resourceId8);
10687
10745
  logger2?.debug("Retrieved view", { hasView: !!sourceView });
10688
10746
  if (!sourceView) {
10689
10747
  throw new Error("Source resource not found");
10690
10748
  }
10691
10749
  } catch (error) {
10692
- logger2?.error("Error getting view", { resourceId: resourceId6, error });
10750
+ logger2?.error("Error getting view", { resourceId: resourceId8, error });
10693
10751
  throw error;
10694
10752
  }
10695
10753
  logger2?.debug("Looking for annotation in resource", {
10696
10754
  annotationId: annotationId4,
10697
- resourceId: resourceId6,
10755
+ resourceId: resourceId8,
10698
10756
  totalAnnotations: sourceView.annotations.annotations.length,
10699
10757
  firstFiveIds: sourceView.annotations.annotations.slice(0, 5).map((a) => a.id)
10700
10758
  });
@@ -10704,9 +10762,9 @@ var AnnotationContext = class {
10704
10762
  throw new Error("Annotation not found in view");
10705
10763
  }
10706
10764
  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})`);
10765
+ logger2?.debug("Validating target resource", { targetSource, expectedResourceId: resourceId8 });
10766
+ if (targetSource !== String(resourceId8)) {
10767
+ throw new Error(`Annotation target resource ID (${targetSource}) does not match expected resource ID (${resourceId8})`);
10710
10768
  }
10711
10769
  const sourceDoc = sourceView.resource;
10712
10770
  const bodySource = getBodySource(annotation.body);
@@ -10722,7 +10780,7 @@ var AnnotationContext = class {
10722
10780
  throw new Error("Source content not found: no storageUri");
10723
10781
  }
10724
10782
  const primaryRep = getPrimaryRepresentation(sourceDoc);
10725
- const { data: sourceContent } = await kb.content.getBinary(resourceId6);
10783
+ const { data: sourceContent } = await kb.content.getBinary(resourceId8);
10726
10784
  const contentStr = decodeRepresentation(Buffer.from(sourceContent), primaryRep?.mediaType ?? "text/plain");
10727
10785
  const targetSelectorRaw = getTargetSelector(annotation.target);
10728
10786
  const targetSelector = Array.isArray(targetSelectorRaw) ? targetSelectorRaw[0] : targetSelectorRaw;
@@ -10769,9 +10827,9 @@ var AnnotationContext = class {
10769
10827
  };
10770
10828
  }
10771
10829
  }
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);
10830
+ logger2?.debug("Building knowledge graph", { resourceId: resourceId8 });
10831
+ const graph = await GraphContext.buildKnowledgeGraph(resourceId8, kb, logger2);
10832
+ const views = deriveViews(graph, String(resourceId8), annotationId4);
10775
10833
  const entityTypeStats = await kb.graph.getEntityTypeStats();
10776
10834
  const entityTypeFrequencies = {};
10777
10835
  for (const stat of entityTypeStats) {
@@ -10808,7 +10866,7 @@ Summary:`;
10808
10866
  const results = await kb.vectors.searchAnnotations(focalEmbedding, {
10809
10867
  limit: 10,
10810
10868
  scoreThreshold: 0.5,
10811
- filter: { excludeResourceId: resourceId6 }
10869
+ filter: { excludeResourceId: resourceId8 }
10812
10870
  });
10813
10871
  const similar = [];
10814
10872
  for (const r of results) {
@@ -10861,10 +10919,10 @@ Summary:`;
10861
10919
  * Get resource annotations from view storage (fast path)
10862
10920
  * Throws if view missing
10863
10921
  */
10864
- static async getResourceAnnotations(resourceId6, kb) {
10865
- const view = await kb.views.get(resourceId6);
10922
+ static async getResourceAnnotations(resourceId8, kb) {
10923
+ const view = await kb.views.get(resourceId8);
10866
10924
  if (!view) {
10867
- throw new Error(`Resource ${resourceId6} not found in view storage`);
10925
+ throw new Error(`Resource ${resourceId8} not found in view storage`);
10868
10926
  }
10869
10927
  return view.annotations;
10870
10928
  }
@@ -10872,8 +10930,8 @@ Summary:`;
10872
10930
  * Get all annotations
10873
10931
  * @returns Array of all annotation objects
10874
10932
  */
10875
- static async getAllAnnotations(resourceId6, kb) {
10876
- const annotations = await this.getResourceAnnotations(resourceId6, kb);
10933
+ static async getAllAnnotations(resourceId8, kb) {
10934
+ const annotations = await this.getResourceAnnotations(resourceId8, kb);
10877
10935
  return this.enrichResolvedReferences(annotations.annotations, kb);
10878
10936
  }
10879
10937
  /**
@@ -10942,8 +11000,8 @@ Summary:`;
10942
11000
  * Get resource stats (version info)
10943
11001
  * @returns Version and timestamp info for the annotations
10944
11002
  */
10945
- static async getResourceStats(resourceId6, kb) {
10946
- const annotations = await this.getResourceAnnotations(resourceId6, kb);
11003
+ static async getResourceStats(resourceId8, kb) {
11004
+ const annotations = await this.getResourceAnnotations(resourceId8, kb);
10947
11005
  return {
10948
11006
  resourceId: annotations.resourceId,
10949
11007
  version: annotations.version,
@@ -10953,15 +11011,15 @@ Summary:`;
10953
11011
  /**
10954
11012
  * Check if resource exists in view storage
10955
11013
  */
10956
- static async resourceExists(resourceId6, kb) {
10957
- return kb.views.exists(resourceId6);
11014
+ static async resourceExists(resourceId8, kb) {
11015
+ return kb.views.exists(resourceId8);
10958
11016
  }
10959
11017
  /**
10960
11018
  * Get a single annotation by ID
10961
11019
  * O(1) lookup using resource ID to access view storage
10962
11020
  */
10963
- static async getAnnotation(annotationId4, resourceId6, kb) {
10964
- const annotations = await this.getResourceAnnotations(resourceId6, kb);
11021
+ static async getAnnotation(annotationId4, resourceId8, kb) {
11022
+ const annotations = await this.getResourceAnnotations(resourceId8, kb);
10965
11023
  return annotations.annotations.find((a) => a.id === annotationId4) || null;
10966
11024
  }
10967
11025
  /**
@@ -10978,8 +11036,8 @@ Summary:`;
10978
11036
  /**
10979
11037
  * Get annotation context (selected text with surrounding context)
10980
11038
  */
10981
- static async getAnnotationContext(annotationId4, resourceId6, contextBefore, contextAfter, kb) {
10982
- const annotation = await this.getAnnotation(annotationId4, resourceId6, kb);
11039
+ static async getAnnotationContext(annotationId4, resourceId8, contextBefore, contextAfter, kb) {
11040
+ const annotation = await this.getAnnotation(annotationId4, resourceId8, kb);
10983
11041
  if (!annotation) {
10984
11042
  throw new Error("Annotation not found");
10985
11043
  }
@@ -11010,8 +11068,8 @@ Summary:`;
11010
11068
  /**
11011
11069
  * Generate AI summary of annotation in context
11012
11070
  */
11013
- static async generateAnnotationSummary(annotationId4, resourceId6, kb, inferenceClient) {
11014
- const annotation = await this.getAnnotation(annotationId4, resourceId6, kb);
11071
+ static async generateAnnotationSummary(annotationId4, resourceId8, kb, inferenceClient) {
11072
+ const annotation = await this.getAnnotation(annotationId4, resourceId8, kb);
11015
11073
  if (!annotation) {
11016
11074
  throw new Error("Annotation not found");
11017
11075
  }
@@ -11092,10 +11150,10 @@ Entity types: ${entityTypes.join(", ")}`;
11092
11150
  return inferenceClient.generateText(summaryPrompt, 500, 0.5);
11093
11151
  }
11094
11152
  };
11095
- async function assembleResourceGraph(kb, resourceId6) {
11153
+ async function assembleResourceGraph(kb, resourceId8) {
11096
11154
  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);
11155
+ const events = await eventQuery.getResourceEvents(resourceId8);
11156
+ const stored = await kb.eventStore.views.materializer.materialize(events, resourceId8);
11099
11157
  if (!stored) return null;
11100
11158
  const annotations = stored.annotations.annotations;
11101
11159
  const entityReferences = annotations.filter((a) => {
@@ -11214,7 +11272,6 @@ function deriveAgentRoster(config2) {
11214
11272
  var BROWSER_CHANNELS = [
11215
11273
  "browse:resource-requested",
11216
11274
  "browse:anchored-text-requested",
11217
- "browse:anchored-text-by-checksum-requested",
11218
11275
  "browse:resources-requested",
11219
11276
  "browse:annotations-requested",
11220
11277
  "browse:annotation-requested",
@@ -11267,7 +11324,6 @@ var Browser = class {
11267
11324
  this.subscriptions.push(
11268
11325
  pipe("browse:resource-requested", (e) => this.handleBrowseResource(e)).subscribe({ error: errorHandler }),
11269
11326
  pipe("browse:anchored-text-requested", (e) => this.handleAnchoredText(e)).subscribe({ error: errorHandler }),
11270
- pipe("browse:anchored-text-by-checksum-requested", (e) => this.handleAnchoredTextByChecksum(e)).subscribe({ error: errorHandler }),
11271
11327
  pipe("browse:resources-requested", (e) => this.handleBrowseResources(e)).subscribe({ error: errorHandler }),
11272
11328
  pipe("browse:annotations-requested", (e) => this.handleBrowseAnnotations(e)).subscribe({ error: errorHandler }),
11273
11329
  pipe("browse:annotation-requested", (e) => this.handleBrowseAnnotation(e)).subscribe({ error: errorHandler }),
@@ -11321,20 +11377,6 @@ var Browser = class {
11321
11377
  * parser nor engine. Read-only over the wire: the Smelter is the sole
11322
11378
  * writer and never answers here.
11323
11379
  */
11324
- async handleAnchoredTextByChecksum(event) {
11325
- try {
11326
- this.eventBus.get("browse:anchored-text-by-checksum-result").next({
11327
- correlationId: event.correlationId,
11328
- response: await this.kb.anchoredText.read(event.checksum)
11329
- });
11330
- } catch (error) {
11331
- this.logger.error("Browse anchored text by checksum failed", { checksum: event.checksum, error: errField(error) });
11332
- this.eventBus.get("browse:anchored-text-by-checksum-failed").next({
11333
- correlationId: event.correlationId,
11334
- message: error instanceof Error ? error.message : String(error)
11335
- });
11336
- }
11337
- }
11338
11380
  async handleBrowseResource(event) {
11339
11381
  try {
11340
11382
  const response = await assembleResourceGraph(this.kb, resourceId(event.resourceId));
@@ -12014,6 +12056,56 @@ var CloneTokenManager = class {
12014
12056
  this.logger.info("CloneTokenManager actor stopped");
12015
12057
  }
12016
12058
  };
12059
+ var MATCHER_CHANNELS = [
12060
+ "match:search-requested"
12061
+ ];
12062
+
12063
+ // src/gatherer.ts
12064
+ var GATHERER_CHANNELS = [
12065
+ "gather:requested",
12066
+ "gather:resource-requested"
12067
+ ];
12068
+
12069
+ // src/service-channels.ts
12070
+ var SMELTER_AWAITED_OPERATIONS = [
12071
+ "browse:resource-requested",
12072
+ "browse:annotations-requested",
12073
+ "browse:resources-requested"
12074
+ ];
12075
+ replyChannelsFor(SMELTER_AWAITED_OPERATIONS);
12076
+ var WEAVER_AWAITED_OPERATIONS = [
12077
+ "browse:resources-requested",
12078
+ "browse:events-requested",
12079
+ "browse:annotations-requested"
12080
+ ];
12081
+ replyChannelsFor(WEAVER_AWAITED_OPERATIONS);
12082
+ var LIBRARIAN_INBOUND_CHANNELS = [
12083
+ ...MATCHER_CHANNELS,
12084
+ ...GATHERER_CHANNELS,
12085
+ "gather:summary-requested",
12086
+ "weave:applied",
12087
+ "smelt:settled"
12088
+ ];
12089
+ replyChannelsFor(LIBRARIAN_INBOUND_CHANNELS);
12090
+ var ARCHIVIST_INBOUND_CHANNELS = [
12091
+ ...STOWER_CHANNELS,
12092
+ ...BROWSER_CHANNELS,
12093
+ ...CLONE_TOKEN_CHANNELS,
12094
+ "mark:create-request",
12095
+ "smelt:settled",
12096
+ // The annotation-context read moved here with the bytes (SINGLE-KB-MOUNT D5).
12097
+ "browse:annotation-context-requested"
12098
+ ];
12099
+ var ARCHIVIST_OUTBOUND_STRAYS = [
12100
+ "mark:body-update-failed",
12101
+ // op keyed 'bind:update-body' (gateway handler re-emits mark:update-body)
12102
+ "yield:move-failed"
12103
+ // yield:mv has no registered operation; failure is direct-subscribed
12104
+ ];
12105
+ var ARCHIVIST_OUTBOUND_CHANNELS = [
12106
+ ...ARCHIVIST_OUTBOUND_STRAYS,
12107
+ ...replyChannelsFor(ARCHIVIST_INBOUND_CHANNELS)
12108
+ ];
12017
12109
  var LIMITS_ENRICH_BUDGET_MS = 1500;
12018
12110
  function createLimitsDiscovery(config2, logger2, options) {
12019
12111
  const clientFactory = createInferenceClient;
@@ -12157,6 +12249,40 @@ function createArchivistServer(deps) {
12157
12249
  res.end();
12158
12250
  });
12159
12251
  }
12252
+
12253
+ // src/fact-pump.ts
12254
+ var import_rxjs5 = __toESM(require_cjs());
12255
+ function createFactPump(facts$, deps) {
12256
+ let depth = 0;
12257
+ const publish = async (event) => {
12258
+ try {
12259
+ const type = event.type;
12260
+ await Promise.all([
12261
+ deps.emit(type, event),
12262
+ ...event.resourceId ? [deps.emit(type, event, event.resourceId)] : []
12263
+ ]);
12264
+ } catch (error) {
12265
+ deps.logger.error("Fact publish failed \u2014 projectors will heal on their next catch-up", {
12266
+ type: event.type,
12267
+ resourceId: event.resourceId,
12268
+ sequenceNumber: event.metadata?.sequenceNumber,
12269
+ error: errField(error)
12270
+ });
12271
+ }
12272
+ };
12273
+ const subscription = facts$.pipe(
12274
+ (0, import_rxjs5.tap)(() => {
12275
+ depth += 1;
12276
+ }),
12277
+ (0, import_rxjs5.concatMap)((event) => (0, import_rxjs5.from)(publish(event).finally(() => {
12278
+ depth -= 1;
12279
+ })))
12280
+ ).subscribe();
12281
+ return {
12282
+ depth: () => depth,
12283
+ unsubscribe: () => subscription.unsubscribe()
12284
+ };
12285
+ }
12160
12286
  async function assertAnnotatableTarget(kb, target) {
12161
12287
  const view = await kb.views.get(resourceId(target));
12162
12288
  const mediaType = getPrimaryRepresentation(view?.resource)?.mediaType;
@@ -12255,8 +12381,8 @@ function registerAnnotationContextHandler(eventBus, kb, parentLogger) {
12255
12381
  }
12256
12382
  function workingTreeContentReads(views, content) {
12257
12383
  return {
12258
- getBinary: async (resourceId6) => {
12259
- const { stream, mediaType } = await resolveRepresentation({ views, content }, resourceId6);
12384
+ getBinary: async (resourceId8) => {
12385
+ const { stream, mediaType } = await resolveRepresentation({ views, content }, resourceId8);
12260
12386
  const chunks = [];
12261
12387
  for await (const chunk of stream) chunks.push(chunk);
12262
12388
  const buf = Buffer.concat(chunks);
@@ -12303,15 +12429,15 @@ function eventAnnotationId(event) {
12303
12429
  return null;
12304
12430
  }
12305
12431
  }
12306
- async function readAnnotationFromView(kb, resourceId6, annotationId4) {
12307
- const allAnnotations = await AnnotationContext.getAllAnnotations(resourceId6, kb);
12432
+ async function readAnnotationFromView(kb, resourceId8, annotationId4) {
12433
+ const allAnnotations = await AnnotationContext.getAllAnnotations(resourceId8, kb);
12308
12434
  return allAnnotations.find((a) => a.id === annotationId4) ?? null;
12309
12435
  }
12310
12436
  function wireEnrichment(eventStore, kb) {
12311
- eventStore.setEnrichEvent(async (event, resourceId6) => {
12437
+ eventStore.setEnrichEvent(async (event, resourceId8) => {
12312
12438
  const annId = eventAnnotationId(event);
12313
12439
  if (annId === null) return event;
12314
- const annotation = await readAnnotationFromView(kb, resourceId6, annId);
12440
+ const annotation = await readAnnotationFromView(kb, resourceId8, annId);
12315
12441
  if (annotation === null) return event;
12316
12442
  return { ...event, annotation };
12317
12443
  });
@@ -12346,34 +12472,8 @@ if (config.services.vectors.type === "memory") {
12346
12472
  }
12347
12473
  var workerSecret = process.env.SEMIONT_WORKER_SECRET ?? "";
12348
12474
  var skipRebuild = process.env.SEMIONT_SKIP_REBUILD === "true";
12349
- var healthPort = 9093;
12475
+ var healthPort = 24103;
12350
12476
  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
12477
  async function authenticate() {
12378
12478
  if (!workerSecret) {
12379
12479
  logger.warn("No SEMIONT_WORKER_SECRET set \u2014 using empty token");
@@ -12412,7 +12512,7 @@ async function main() {
12412
12512
  const { initObservabilityNode } = await import('@semiont/observability/node');
12413
12513
  initObservabilityNode({ serviceName: "semiont-archivist" });
12414
12514
  logger.info("Authenticating", { baseUrl });
12415
- const tokenSubject = new import_rxjs5.BehaviorSubject(accessToken(await authenticate()));
12515
+ const tokenSubject = new import_rxjs6.BehaviorSubject(accessToken(await authenticate()));
12416
12516
  logger.info("Authenticated");
12417
12517
  const refreshToken = async () => {
12418
12518
  const token = await authenticate();
@@ -12487,18 +12587,22 @@ async function main() {
12487
12587
  const httpTransport = new HttpTransport({
12488
12588
  baseUrl: baseUrl$1(baseUrl),
12489
12589
  token$: tokenSubject,
12490
- tokenRefresher: refreshToken
12590
+ tokenRefresher: refreshToken,
12591
+ // Exactly the inbound roster — never the full bridged set, whose global
12592
+ // reply fan-out is the worker-OOM failure mode. This process awaits no
12593
+ // wire replies (busRequest's isSubscribed gate fails fast if one is ever
12594
+ // added without growing the roster), so inbound IS the subscription.
12595
+ channels: ARCHIVIST_INBOUND_CHANNELS
12491
12596
  });
12492
12597
  const pumps = [];
12493
- httpTransport.actor.addChannels([...INBOUND_CHANNELS]);
12494
- for (const channel of INBOUND_CHANNELS) {
12598
+ for (const channel of ARCHIVIST_INBOUND_CHANNELS) {
12495
12599
  pumps.push(
12496
12600
  httpTransport.stream(channel).subscribe((payload) => {
12497
12601
  localBus.get(channel).next(payload);
12498
12602
  })
12499
12603
  );
12500
12604
  }
12501
- const outbound = outboundChannels();
12605
+ const outbound = ARCHIVIST_OUTBOUND_CHANNELS;
12502
12606
  for (const channel of outbound) {
12503
12607
  pumps.push(
12504
12608
  localBus.get(channel).subscribe((payload) => {
@@ -12508,26 +12612,13 @@ async function main() {
12508
12612
  })
12509
12613
  );
12510
12614
  }
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()
12615
+ const factPump = createFactPump(
12616
+ (0, import_rxjs6.merge)(...PERSISTED_EVENT_TYPES.map((type) => localBus.getDomainEvent(type))),
12617
+ { emit: (channel, payload, scope) => httpTransport.emit(channel, payload, scope), logger }
12529
12618
  );
12530
- logger.info("Bus pumps attached", { inbound: INBOUND_CHANNELS.length, outbound: outbound.length, facts: PERSISTED_EVENT_TYPES.length });
12619
+ pumps.push({ unsubscribe: () => factPump.unsubscribe() });
12620
+ registerFactPumpDepthProvider(() => factPump.depth());
12621
+ logger.info("Bus pumps attached", { inbound: ARCHIVIST_INBOUND_CHANNELS.length, outbound: outbound.length, facts: PERSISTED_EVENT_TYPES.length });
12531
12622
  const server = createArchivistServer({
12532
12623
  events: eventStore.log,
12533
12624
  content,
@@ -12558,7 +12649,7 @@ async function main() {
12558
12649
  };
12559
12650
  process.on("SIGTERM", shutdown);
12560
12651
  process.on("SIGINT", shutdown);
12561
- logger.info("Archivist serving", { channels: INBOUND_CHANNELS.length });
12652
+ logger.info("Archivist serving", { channels: ARCHIVIST_INBOUND_CHANNELS.length });
12562
12653
  }
12563
12654
  main().catch((error) => {
12564
12655
  logger.error("Fatal", { error: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : void 0 });