@indexnetwork/protocol 4.5.0-rc.322.1 → 4.5.0-rc.324.1

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 (111) hide show
  1. package/dist/agent/agent.tools.js +1 -1
  2. package/dist/agent/agent.tools.js.map +1 -1
  3. package/dist/chat/chat.interrupt.classifier.js +1 -1
  4. package/dist/chat/chat.interrupt.classifier.js.map +1 -1
  5. package/dist/chat/chat.suggester.js +3 -3
  6. package/dist/chat/chat.suggester.js.map +1 -1
  7. package/dist/chat/chat.title.generator.js +2 -2
  8. package/dist/chat/chat.title.generator.js.map +1 -1
  9. package/dist/contact/contact.tools.js +1 -1
  10. package/dist/contact/contact.tools.js.map +1 -1
  11. package/dist/enrichment/enrichment.graph.d.ts.map +1 -1
  12. package/dist/enrichment/enrichment.graph.js +9 -3
  13. package/dist/enrichment/enrichment.graph.js.map +1 -1
  14. package/dist/index.d.ts +2 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +1 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/integration/integration.tools.js +1 -1
  19. package/dist/integration/integration.tools.js.map +1 -1
  20. package/dist/intent/intent.graph.d.ts.map +1 -1
  21. package/dist/intent/intent.graph.js +12 -10
  22. package/dist/intent/intent.graph.js.map +1 -1
  23. package/dist/intent/intent.indexer.d.ts.map +1 -1
  24. package/dist/intent/intent.indexer.js +4 -3
  25. package/dist/intent/intent.indexer.js.map +1 -1
  26. package/dist/intent/intent.inferrer.d.ts.map +1 -1
  27. package/dist/intent/intent.inferrer.js +2 -1
  28. package/dist/intent/intent.inferrer.js.map +1 -1
  29. package/dist/intent/intent.reconciler.d.ts.map +1 -1
  30. package/dist/intent/intent.reconciler.js +5 -4
  31. package/dist/intent/intent.reconciler.js.map +1 -1
  32. package/dist/intent/intent.verifier.d.ts.map +1 -1
  33. package/dist/intent/intent.verifier.js +4 -3
  34. package/dist/intent/intent.verifier.js.map +1 -1
  35. package/dist/maintenance/maintenance.graph.d.ts.map +1 -1
  36. package/dist/maintenance/maintenance.graph.js +27 -5
  37. package/dist/maintenance/maintenance.graph.js.map +1 -1
  38. package/dist/mcp/mcp.server.d.ts.map +1 -1
  39. package/dist/mcp/mcp.server.js +5 -4
  40. package/dist/mcp/mcp.server.js.map +1 -1
  41. package/dist/negotiation/insight.generator.js +2 -2
  42. package/dist/negotiation/insight.generator.js.map +1 -1
  43. package/dist/negotiation/negotiation.graph.d.ts.map +1 -1
  44. package/dist/negotiation/negotiation.graph.js +15 -11
  45. package/dist/negotiation/negotiation.graph.js.map +1 -1
  46. package/dist/negotiation/negotiation.tools.js +1 -1
  47. package/dist/negotiation/negotiation.tools.js.map +1 -1
  48. package/dist/network/network.recommender.d.ts.map +1 -1
  49. package/dist/network/network.recommender.js +5 -4
  50. package/dist/network/network.recommender.js.map +1 -1
  51. package/dist/network/network.tools.d.ts.map +1 -1
  52. package/dist/network/network.tools.js +4 -2
  53. package/dist/network/network.tools.js.map +1 -1
  54. package/dist/opportunity/feed/feed.graph.d.ts.map +1 -1
  55. package/dist/opportunity/feed/feed.graph.js +30 -23
  56. package/dist/opportunity/feed/feed.graph.js.map +1 -1
  57. package/dist/opportunity/opportunity.discover.d.ts.map +1 -1
  58. package/dist/opportunity/opportunity.discover.js +6 -4
  59. package/dist/opportunity/opportunity.discover.js.map +1 -1
  60. package/dist/opportunity/opportunity.enricher.js +2 -2
  61. package/dist/opportunity/opportunity.enricher.js.map +1 -1
  62. package/dist/opportunity/opportunity.evaluator.d.ts.map +1 -1
  63. package/dist/opportunity/opportunity.evaluator.js +9 -7
  64. package/dist/opportunity/opportunity.evaluator.js.map +1 -1
  65. package/dist/opportunity/opportunity.graph.d.ts.map +1 -1
  66. package/dist/opportunity/opportunity.graph.js +123 -105
  67. package/dist/opportunity/opportunity.graph.js.map +1 -1
  68. package/dist/opportunity/opportunity.introducer.js +5 -5
  69. package/dist/opportunity/opportunity.introducer.js.map +1 -1
  70. package/dist/opportunity/opportunity.persist.js +2 -2
  71. package/dist/opportunity/opportunity.persist.js.map +1 -1
  72. package/dist/opportunity/opportunity.presenter.d.ts.map +1 -1
  73. package/dist/opportunity/opportunity.presenter.js +4 -2
  74. package/dist/opportunity/opportunity.presenter.js.map +1 -1
  75. package/dist/opportunity/opportunity.tools.d.ts.map +1 -1
  76. package/dist/opportunity/opportunity.tools.js +2 -1
  77. package/dist/opportunity/opportunity.tools.js.map +1 -1
  78. package/dist/opportunity/opportunity.utils.d.ts.map +1 -1
  79. package/dist/opportunity/opportunity.utils.js +29 -5
  80. package/dist/opportunity/opportunity.utils.js.map +1 -1
  81. package/dist/premise/premise.analyzer.d.ts.map +1 -1
  82. package/dist/premise/premise.analyzer.js +3 -2
  83. package/dist/premise/premise.analyzer.js.map +1 -1
  84. package/dist/premise/premise.decomposer.d.ts.map +1 -1
  85. package/dist/premise/premise.decomposer.js +12 -3
  86. package/dist/premise/premise.decomposer.js.map +1 -1
  87. package/dist/premise/premise.graph.d.ts.map +1 -1
  88. package/dist/premise/premise.graph.js +19 -9
  89. package/dist/premise/premise.graph.js.map +1 -1
  90. package/dist/premise/premise.indexer.d.ts.map +1 -1
  91. package/dist/premise/premise.indexer.js +2 -1
  92. package/dist/premise/premise.indexer.js.map +1 -1
  93. package/dist/premise/premise.tools.d.ts.map +1 -1
  94. package/dist/premise/premise.tools.js +8 -4
  95. package/dist/premise/premise.tools.js.map +1 -1
  96. package/dist/shared/agent/tool.factory.d.ts.map +1 -1
  97. package/dist/shared/agent/tool.factory.js +4 -2
  98. package/dist/shared/agent/tool.factory.js.map +1 -1
  99. package/dist/shared/agent/tool.registry.d.ts.map +1 -1
  100. package/dist/shared/agent/tool.registry.js +6 -4
  101. package/dist/shared/agent/tool.registry.js.map +1 -1
  102. package/dist/shared/interfaces/database.interface.d.ts +1 -1
  103. package/dist/shared/interfaces/database.interface.js.map +1 -1
  104. package/dist/shared/observability/log.d.ts +3 -2
  105. package/dist/shared/observability/log.d.ts.map +1 -1
  106. package/dist/shared/observability/log.js +72 -9
  107. package/dist/shared/observability/log.js.map +1 -1
  108. package/dist/shared/observability/protocol.logger.d.ts.map +1 -1
  109. package/dist/shared/observability/protocol.logger.js +5 -3
  110. package/dist/shared/observability/protocol.logger.js.map +1 -1
  111. package/package.json +5 -5
@@ -30,6 +30,24 @@ import { renderNetworkContext } from '../shared/network/metadata.renderer.js';
30
30
  import { requestContext } from "../shared/observability/request-context.js";
31
31
  import { mergeOpportunityEvidence, withCandidateEvidence, withMatchedStrategies } from './opportunity.evidence.js';
32
32
  const logger = protocolLogger('OpportunityGraph');
33
+ const prepLog = protocolLogger('OpportunityGraph:Prep');
34
+ const scopeLog = protocolLogger('OpportunityGraph:Scope');
35
+ const resolveLog = protocolLogger('OpportunityGraph:Resolve');
36
+ const discoveryLog = protocolLogger('OpportunityGraph:Discovery');
37
+ const evaluationLog = protocolLogger('OpportunityGraph:Evaluation');
38
+ const negotiateLog = protocolLogger('OpportunityGraph:Negotiate');
39
+ const rankingLog = protocolLogger('OpportunityGraph:Ranking');
40
+ const introValidationLog = protocolLogger('OpportunityGraph:IntroValidation');
41
+ const introEvaluationLog = protocolLogger('OpportunityGraph:IntroEvaluation');
42
+ const persistLog = protocolLogger('OpportunityGraph:Persist');
43
+ const persistPathLog = protocolLogger('OpportunityGraph:Persist:PathSelect');
44
+ const persistDedupLog = protocolLogger('OpportunityGraph:Persist:Dedup');
45
+ const readLog = protocolLogger('OpportunityGraph:Read');
46
+ const updateLog = protocolLogger('OpportunityGraph:Update');
47
+ const deleteLog = protocolLogger('OpportunityGraph:Delete');
48
+ const sendLog = protocolLogger('OpportunityGraph:Send');
49
+ const negotiateExistingLog = protocolLogger('OpportunityGraph:NegotiateExisting');
50
+ const routingLog = protocolLogger('OpportunityGraph:Routing');
33
51
  /** Time window for persist-node dedup. Suppresses a second opportunity with the same person while a recent one (within 30 days) is still in flight, so a person is not re-surfaced multiple times within a month (EDG-23). */
34
52
  const DEDUP_WINDOW_MS = 30 * 24 * 60 * 60 * 1000;
35
53
  /** Default cap for source premises used by premise-to-premise discovery. Prevents BACKEND-5-style fan-out. */
@@ -173,7 +191,7 @@ export class OpportunityGraphFactory {
173
191
  * Fetches user's network memberships and validates requirements.
174
192
  * Returns empty if user has no network memberships (requirement).
175
193
  */
176
- const prepNode = withNodeTrace("opportunity-prep", async (state) => timed("OpportunityGraph.prep", async () => withCallLogging(logger, '[Graph:Prep] prepNode', {
194
+ const prepNode = withNodeTrace("opportunity-prep", async (state) => timed("OpportunityGraph.prep", async () => withCallLogging(prepLog, 'prepNode', {
177
195
  userId: state.userId,
178
196
  hasSearchQuery: !!state.searchQuery,
179
197
  requestedIndexId: state.networkId ?? undefined,
@@ -183,7 +201,7 @@ export class OpportunityGraphFactory {
183
201
  const memberships = await this.database.getNetworkMemberships(state.userId);
184
202
  const userNetworkIds = memberships.map(m => m.networkId);
185
203
  if (userNetworkIds.length === 0) {
186
- logger.verbose('[Graph:Prep] User has no network memberships - cannot find opportunities');
204
+ prepLog.verbose('User has no network memberships - cannot find opportunities');
187
205
  return {
188
206
  userNetworks: [],
189
207
  sourceProfile: null,
@@ -238,7 +256,7 @@ export class OpportunityGraphFactory {
238
256
  };
239
257
  }, { context: { userId: state.userId }, logOutput: true }).catch((error) => {
240
258
  const errMsg = error instanceof Error ? error.message : String(error);
241
- logger.error('[Graph:Prep] Failed', { error });
259
+ prepLog.error('Failed', { error });
242
260
  return {
243
261
  error: 'Failed to prepare opportunity search. Please try again.',
244
262
  trace: [{
@@ -263,7 +281,7 @@ export class OpportunityGraphFactory {
263
281
  */
264
282
  const scopeNode = withNodeTrace("opportunity-scope", async (state) => {
265
283
  return timed("OpportunityGraph.scope", async () => {
266
- logger.verbose('[Graph:Scope] Determining search scope', {
284
+ scopeLog.verbose('Determining search scope', {
267
285
  requestedIndexId: state.networkId,
268
286
  userNetworksCount: state.userNetworks.length,
269
287
  });
@@ -274,7 +292,7 @@ export class OpportunityGraphFactory {
274
292
  const isInScope = state.userNetworks.includes(state.networkId);
275
293
  const isOwner = !isInScope && await this.database.isIndexOwner(state.networkId, state.userId);
276
294
  if (!isInScope && !isOwner) {
277
- logger.warn('[Graph:Scope] User not member of requested network', {
295
+ scopeLog.warn('User not member of requested network', {
278
296
  networkId: state.networkId,
279
297
  });
280
298
  return {
@@ -290,7 +308,7 @@ export class OpportunityGraphFactory {
290
308
  // reaches networks outside the agent's bound scope.
291
309
  const allowed = new Set(state.indexScope);
292
310
  targetIndexIds = state.userNetworks.filter((n) => allowed.has(n));
293
- logger.verbose('[Graph:Scope] Applied indexScope intersection', {
311
+ scopeLog.verbose('Applied indexScope intersection', {
294
312
  indexScopeCount: state.indexScope.length,
295
313
  userNetworksCount: state.userNetworks.length,
296
314
  targetCount: targetIndexIds.length,
@@ -310,7 +328,7 @@ export class OpportunityGraphFactory {
310
328
  memberCount,
311
329
  };
312
330
  }));
313
- logger.verbose('[Graph:Scope] Scope determined', {
331
+ scopeLog.verbose('Scope determined', {
314
332
  targetIndexesCount: targetNetworks.length,
315
333
  indexes: targetNetworks.map(i => i.title),
316
334
  });
@@ -327,7 +345,7 @@ export class OpportunityGraphFactory {
327
345
  }
328
346
  }
329
347
  catch (err) {
330
- logger.warn('[Graph:Scope] Failed to load intent index scores', { triggerIntentId: state.triggerIntentId, error: err });
348
+ scopeLog.warn('Failed to load intent index scores', { triggerIntentId: state.triggerIntentId, error: err });
331
349
  }
332
350
  }
333
351
  else if (state.searchQuery?.trim()) {
@@ -382,7 +400,7 @@ export class OpportunityGraphFactory {
382
400
  }
383
401
  }
384
402
  catch (err) {
385
- logger.warn('[Graph:Scope] Failed to score query against indexes', { error: err });
403
+ scopeLog.warn('Failed to score query against indexes', { error: err });
386
404
  }
387
405
  }
388
406
  const totalMembers = targetNetworks.reduce((sum, i) => sum + i.memberCount, 0);
@@ -398,7 +416,7 @@ export class OpportunityGraphFactory {
398
416
  }
399
417
  catch (error) {
400
418
  const errMsg = error instanceof Error ? error.message : String(error);
401
- logger.error('[Graph:Scope] Failed', { error });
419
+ scopeLog.error('Failed', { error });
402
420
  return {
403
421
  targetNetworks: [],
404
422
  error: 'Failed to determine search scope.',
@@ -424,7 +442,7 @@ export class OpportunityGraphFactory {
424
442
  */
425
443
  const resolveNode = withNodeTrace("opportunity-resolve", async (state) => {
426
444
  return timed("OpportunityGraph.resolve", async () => {
427
- logger.verbose('[Graph:Resolve] Resolving intent and network membership', {
445
+ resolveLog.verbose('Resolving intent and network membership', {
428
446
  triggerIntentId: state.triggerIntentId,
429
447
  hasSearchQuery: !!state.searchQuery,
430
448
  indexedIntentsCount: state.indexedIntents.length,
@@ -458,7 +476,7 @@ export class OpportunityGraphFactory {
458
476
  discoverySource,
459
477
  };
460
478
  }
461
- logger.warn('[Graph:Resolve] No intent matched search query; leaving resolvedIntentId unset', {
479
+ resolveLog.warn('No intent matched search query; leaving resolvedIntentId unset', {
462
480
  searchQuery: state.searchQuery,
463
481
  indexedIntentsCount: state.indexedIntents.length,
464
482
  });
@@ -471,7 +489,7 @@ export class OpportunityGraphFactory {
471
489
  }
472
490
  catch (err) {
473
491
  const errMsg = err instanceof Error ? err.message : String(err);
474
- logger.error('[Graph:Resolve] Failed', {
492
+ resolveLog.error('Failed', {
475
493
  triggerIntentId: state.triggerIntentId,
476
494
  searchQuery: state.searchQuery,
477
495
  error: err,
@@ -509,7 +527,7 @@ export class OpportunityGraphFactory {
509
527
  if (!state.targetUserId)
510
528
  return candidates;
511
529
  const filtered = candidates.filter(c => c.candidateUserId === state.targetUserId);
512
- logger.verbose('[Graph:Discovery] targetUserId filter applied', {
530
+ discoveryLog.verbose('targetUserId filter applied', {
513
531
  targetUserId: state.targetUserId,
514
532
  before: candidates.length,
515
533
  after: filtered.length,
@@ -520,14 +538,14 @@ export class OpportunityGraphFactory {
520
538
  let discoveryLensInput;
521
539
  // Shared variable to capture HyDE output (lenses + documents) for trace entries
522
540
  let discoveryHydeOutput;
523
- logger.verbose('[Graph:Discovery] Starting semantic search', {
541
+ discoveryLog.verbose('Starting semantic search', {
524
542
  targetIndexesCount: state.targetNetworks.length,
525
543
  discoverySource: state.discoverySource,
526
544
  searchQueryPreview: state.searchQuery?.trim().slice(0, 60) ?? '(none)',
527
545
  });
528
546
  try {
529
547
  if (state.targetNetworks.length === 0) {
530
- logger.warn('[Graph:Discovery] No target indexes for search');
548
+ discoveryLog.warn('No target indexes for search');
531
549
  return { candidates: [] };
532
550
  }
533
551
  // ── Direct-connection fast path ──
@@ -535,7 +553,7 @@ export class OpportunityGraphFactory {
535
553
  // and construct candidates directly from shared networks.
536
554
  if (state.targetUserId) {
537
555
  if (state.targetUserId === discoveryUserId) {
538
- logger.warn('[Graph:Discovery] Direct-connection target matches discoverer; skipping self-match', {
556
+ discoveryLog.warn('Direct-connection target matches discoverer; skipping self-match', {
539
557
  targetUserId: state.targetUserId,
540
558
  });
541
559
  return {
@@ -547,7 +565,7 @@ export class OpportunityGraphFactory {
547
565
  }],
548
566
  };
549
567
  }
550
- logger.verbose('[Graph:Discovery] Direct-connection mode — bypassing vector search', {
568
+ discoveryLog.verbose('Direct-connection mode — bypassing vector search', {
551
569
  targetUserId: state.targetUserId,
552
570
  });
553
571
  const targetMemberships = await this.database.getNetworkMemberships(state.targetUserId);
@@ -556,7 +574,7 @@ export class OpportunityGraphFactory {
556
574
  .filter(ti => targetUserIndexIds.includes(ti.networkId))
557
575
  .map(ti => ti.networkId);
558
576
  if (sharedIndexIds.length === 0) {
559
- logger.warn('[Graph:Discovery] Target user shares no indexes with discoverer', {
577
+ discoveryLog.warn('Target user shares no indexes with discoverer', {
560
578
  targetUserId: state.targetUserId,
561
579
  discovererIndexes: state.targetNetworks.map(ti => ti.networkId),
562
580
  });
@@ -603,7 +621,7 @@ export class OpportunityGraphFactory {
603
621
  discoverySource: 'query',
604
622
  }));
605
623
  }
606
- logger.verbose('[Graph:Discovery] Direct candidates constructed', {
624
+ discoveryLog.verbose('Direct candidates constructed', {
607
625
  count: directCandidates.length,
608
626
  sharedIndexes: sharedIndexIds.length,
609
627
  targetIntents: targetIntents.length,
@@ -631,11 +649,11 @@ export class OpportunityGraphFactory {
631
649
  if (state.discoverySource === 'context') {
632
650
  // Context discovery: HyDE (when search query exists) + premise-to-premise.
633
651
  if (state.searchQuery?.trim()) {
634
- logger.verbose('[Graph:Discovery] Context source with searchQuery → running query HyDE + premise paths', {
652
+ discoveryLog.verbose('Context source with searchQuery → running query HyDE + premise paths', {
635
653
  searchQuery: state.searchQuery.trim().substring(0, 80),
636
654
  });
637
655
  const queryCandidates = await runQueryHydeDiscovery();
638
- logger.verbose('[Graph:Discovery] Query HyDE path complete', { candidatesFound: queryCandidates.length });
656
+ discoveryLog.verbose('Query HyDE path complete', { candidatesFound: queryCandidates.length });
639
657
  // Build trace entries for this path
640
658
  const traceEntries = [];
641
659
  // Lens input trace (captured from runQueryHydeDiscovery)
@@ -727,7 +745,7 @@ export class OpportunityGraphFactory {
727
745
  const searchText = state.searchQuery?.trim() ?? '';
728
746
  if (!searchText)
729
747
  return [];
730
- logger.verbose('[Graph:Discovery] runQueryHydeDiscovery start', { searchText: searchText.slice(0, 80) });
748
+ discoveryLog.verbose('runQueryHydeDiscovery start', { searchText: searchText.slice(0, 80) });
731
749
  const discovererContext = buildDiscovererContext(state.sourceProfile, state.indexedIntents);
732
750
  discoveryLensInput = {
733
751
  profileContext: discovererContext,
@@ -746,7 +764,7 @@ export class OpportunityGraphFactory {
746
764
  hydeDocuments: (hydeResult.hydeDocuments ?? {}),
747
765
  };
748
766
  const embeddingKeys = hydeEmbeddings ? Object.keys(hydeEmbeddings) : [];
749
- logger.verbose('[Graph:Discovery] HyDE generator result', {
767
+ discoveryLog.verbose('HyDE generator result', {
750
768
  lensCount: embeddingKeys.length,
751
769
  lenses: embeddingKeys,
752
770
  });
@@ -796,7 +814,7 @@ export class OpportunityGraphFactory {
796
814
  }));
797
815
  const intentCount = all.filter((c) => c.candidateIntentId).length;
798
816
  const premiseCount = all.filter((c) => c.candidatePremiseId).length;
799
- logger.verbose('[Graph:Discovery] searchWithHydeEmbeddings raw results', {
817
+ discoveryLog.verbose('searchWithHydeEmbeddings raw results', {
800
818
  total: all.length,
801
819
  fromIntent: intentCount,
802
820
  fromPremise: premiseCount,
@@ -824,7 +842,7 @@ export class OpportunityGraphFactory {
824
842
  return [];
825
843
  const sourceLimit = getSourcePremiseDiscoveryLimit();
826
844
  if (sourceLimit === 0) {
827
- logger.verbose('[Graph:Discovery] runPremiseDiscovery disabled by DISCOVERY_SOURCE_PREMISE_LIMIT=0');
845
+ discoveryLog.verbose('runPremiseDiscovery disabled by DISCOVERY_SOURCE_PREMISE_LIMIT=0');
828
846
  return [];
829
847
  }
830
848
  const sourcePremisesFromDb = self.database.getPremisesForUserInNetworks
@@ -838,7 +856,7 @@ export class OpportunityGraphFactory {
838
856
  : (state.sourcePremises ?? []).slice(0, sourceLimit));
839
857
  if (sourcePremises.length === 0)
840
858
  return [];
841
- logger.verbose('[Graph:Discovery] runPremiseDiscovery start', {
859
+ discoveryLog.verbose('runPremiseDiscovery start', {
842
860
  premiseCount: sourcePremises.length,
843
861
  sourceLimit,
844
862
  targetNetworks: targetNetworkIds.length,
@@ -882,7 +900,7 @@ export class OpportunityGraphFactory {
882
900
  }
883
901
  }
884
902
  const deduped = Array.from(byKey.values());
885
- logger.verbose('[Graph:Discovery] runPremiseDiscovery complete', {
903
+ discoveryLog.verbose('runPremiseDiscovery complete', {
886
904
  sourcePremiseCount: sourcePremises.length,
887
905
  rawCount: premiseCandidates.length,
888
906
  dedupedCount: deduped.length,
@@ -904,7 +922,7 @@ export class OpportunityGraphFactory {
904
922
  const targetNetworkIds = state.targetNetworks.map(t => t.networkId);
905
923
  if (targetNetworkIds.length === 0)
906
924
  return [];
907
- logger.verbose('[Graph:Discovery] runContextToIntentDiscovery start', {
925
+ discoveryLog.verbose('runContextToIntentDiscovery start', {
908
926
  contextCount: state.sourceContexts.length,
909
927
  targetNetworks: targetNetworkIds.length,
910
928
  });
@@ -974,7 +992,7 @@ export class OpportunityGraphFactory {
974
992
  }
975
993
  }
976
994
  const deduped = Array.from(byKey.values());
977
- logger.verbose('[Graph:Discovery] runContextToIntentDiscovery complete', {
995
+ discoveryLog.verbose('runContextToIntentDiscovery complete', {
978
996
  rawCount: contextCandidates.length,
979
997
  dedupedCount: deduped.length,
980
998
  });
@@ -1024,7 +1042,7 @@ export class OpportunityGraphFactory {
1024
1042
  : state.indexedIntents[0];
1025
1043
  const searchText = state.searchQuery ?? resolvedIntent?.payload ?? '';
1026
1044
  if (!searchText) {
1027
- logger.warn('[Graph:Discovery] No search text available for intent path');
1045
+ discoveryLog.warn('No search text available for intent path');
1028
1046
  const [premiseCands, contextCands] = await Promise.all([
1029
1047
  runPremiseDiscovery(),
1030
1048
  runContextToIntentDiscovery(),
@@ -1117,7 +1135,7 @@ export class OpportunityGraphFactory {
1117
1135
  }
1118
1136
  }
1119
1137
  const candidates = Array.from(byUserAndIndex.values());
1120
- logger.verbose('[Graph:Discovery] Intent-path discovery complete', { candidatesFound: candidates.length });
1138
+ discoveryLog.verbose('Intent-path discovery complete', { candidatesFound: candidates.length });
1121
1139
  const usedLenses = Object.keys(hydeEmbeddings);
1122
1140
  // Build trace with individual candidate similarity scores
1123
1141
  const traceEntries = [];
@@ -1210,7 +1228,7 @@ export class OpportunityGraphFactory {
1210
1228
  }
1211
1229
  catch (error) {
1212
1230
  const errMsg = error instanceof Error ? error.message : String(error);
1213
- logger.error('[Graph:Discovery] Failed', { error });
1231
+ discoveryLog.error('Failed', { error });
1214
1232
  return {
1215
1233
  candidates: [],
1216
1234
  error: 'Failed to search for candidates.',
@@ -1236,11 +1254,11 @@ export class OpportunityGraphFactory {
1236
1254
  const evaluationNode = async (state) => {
1237
1255
  return timed("OpportunityGraph.evaluation", async () => {
1238
1256
  const startTime = Date.now();
1239
- logger.verbose('[Graph:Evaluation] Starting evaluation', {
1257
+ evaluationLog.verbose('Starting evaluation', {
1240
1258
  candidatesCount: state.candidates.length,
1241
1259
  });
1242
1260
  if (state.candidates.length === 0) {
1243
- logger.verbose('[Graph:Evaluation] No candidates to evaluate');
1261
+ evaluationLog.verbose('No candidates to evaluate');
1244
1262
  return { evaluatedOpportunities: [], agentTimings: [] };
1245
1263
  }
1246
1264
  // Batch candidates to avoid timeout - evaluate top 25 per batch, store remaining
@@ -1270,7 +1288,7 @@ export class OpportunityGraphFactory {
1270
1288
  // Re-sort by similarity descending (Map iteration order doesn't guarantee sort)
1271
1289
  dedupedCandidates.sort((a, b) => b.similarity - a.similarity);
1272
1290
  if (dedupedCandidates.length < sortedCandidates.length) {
1273
- logger.info("[Graph:Evaluation] Deduped candidates by userId", {
1291
+ evaluationLog.info("Deduped candidates by userId", {
1274
1292
  before: sortedCandidates.length,
1275
1293
  after: dedupedCandidates.length,
1276
1294
  removed: sortedCandidates.length - dedupedCandidates.length,
@@ -1284,12 +1302,12 @@ export class OpportunityGraphFactory {
1284
1302
  const queryRemaining = remaining.filter((c) => c.discoverySource === 'query' || c.discoverySource == null);
1285
1303
  const effectiveRemaining = isQueryDriven && queryRemaining.length === 0 ? [] : remaining;
1286
1304
  if (isQueryDriven && remaining.length > 0 && queryRemaining.length === 0) {
1287
- logger.info("[Graph:Evaluation] Early termination: no query-sourced candidates remain", {
1305
+ evaluationLog.info("Early termination: no query-sourced candidates remain", {
1288
1306
  droppedCandidates: remaining.length,
1289
1307
  });
1290
1308
  }
1291
1309
  if (effectiveRemaining.length > 0) {
1292
- logger.verbose('[Graph:Evaluation] Batched candidates for evaluation', {
1310
+ evaluationLog.verbose('Batched candidates for evaluation', {
1293
1311
  evaluating: batchToEvaluate.length,
1294
1312
  remaining: effectiveRemaining.length,
1295
1313
  total: sortedCandidates.length,
@@ -1384,7 +1402,7 @@ export class OpportunityGraphFactory {
1384
1402
  let pairwiseOpportunities;
1385
1403
  if (runParallel) {
1386
1404
  // Experimental: one LLM call per candidate, all fired in parallel
1387
- logger.verbose('[Graph:Evaluation] Running parallel evaluation', { candidates: candidateEntities.length });
1405
+ evaluationLog.verbose('Running parallel evaluation', { candidates: candidateEntities.length });
1388
1406
  const parallelResults = await Promise.all(candidateEntities.map((candidateEntity) => {
1389
1407
  const input = {
1390
1408
  discovererId: discoveryUserId,
@@ -1411,7 +1429,7 @@ export class OpportunityGraphFactory {
1411
1429
  const _errMsg = err instanceof Error ? err.message : String(err);
1412
1430
  agentTimingsAccum.push({ name: 'opportunity.evaluator', durationMs: _evalDuration });
1413
1431
  _traceEmitter?.({ type: "agent_end", name: "opportunity-evaluator", durationMs: _evalDuration, summary: `${_candidateName}: error — ${_errMsg}` });
1414
- logger.warn('[Graph:Evaluation] Parallel eval failed for candidate', {
1432
+ evaluationLog.warn('Parallel eval failed for candidate', {
1415
1433
  candidateUserId: candidateEntity.userId,
1416
1434
  error: err,
1417
1435
  });
@@ -1484,7 +1502,7 @@ export class OpportunityGraphFactory {
1484
1502
  pairwiseOpportunities.push(op);
1485
1503
  }
1486
1504
  else {
1487
- logger.warn('[Graph:Evaluation] Splitting multi-actor opportunity; LLM returned bundled actors instead of one-per-candidate', {
1505
+ evaluationLog.warn('Splitting multi-actor opportunity; LLM returned bundled actors instead of one-per-candidate', {
1488
1506
  actorCount: nonViewerActors.length,
1489
1507
  userIds: nonViewerActors.map(a => a.userId),
1490
1508
  });
@@ -1555,7 +1573,7 @@ export class OpportunityGraphFactory {
1555
1573
  }),
1556
1574
  }));
1557
1575
  const passed = evaluatedOpportunities.filter((o) => o.score >= minScore);
1558
- logger.verbose('[Graph:Evaluation] Evaluation complete', {
1576
+ evaluationLog.verbose('Evaluation complete', {
1559
1577
  evaluatedCount: evaluatedOpportunities.length,
1560
1578
  passed: passed.length,
1561
1579
  });
@@ -1644,7 +1662,7 @@ export class OpportunityGraphFactory {
1644
1662
  }
1645
1663
  catch (error) {
1646
1664
  const errMsg = error instanceof Error ? error.message : String(error);
1647
- logger.error('[Graph:Evaluation] Failed', { error });
1665
+ evaluationLog.error('Failed', { error });
1648
1666
  return {
1649
1667
  evaluatedOpportunities: [],
1650
1668
  error: 'Failed to evaluate candidates.',
@@ -1700,7 +1718,7 @@ export class OpportunityGraphFactory {
1700
1718
  };
1701
1719
  // Build candidates from persisted opportunities. Each opportunity carries its DB id
1702
1720
  // so the negotiation graph's finalize node can update its status from the outcome.
1703
- logger.verbose('[Graph:Negotiate] Building candidates from opportunities', {
1721
+ negotiateLog.verbose('Building candidates from opportunities', {
1704
1722
  opportunityCount: state.opportunities.length,
1705
1723
  discoveryUserId,
1706
1724
  });
@@ -1710,7 +1728,7 @@ export class OpportunityGraphFactory {
1710
1728
  const introducerActors = opp.actors
1711
1729
  .filter(a => a.role === 'introducer');
1712
1730
  if (introducerActors.length > 0 && !introducerActors.every(a => a.approved === true)) {
1713
- logger.verbose('[Graph:Negotiate] Skipping opportunity: introducer not approved', {
1731
+ negotiateLog.verbose('Skipping opportunity: introducer not approved', {
1714
1732
  opportunityId: opp.id,
1715
1733
  introducerCount: introducerActors.length,
1716
1734
  approvedCount: introducerActors.filter(a => a.approved === true).length,
@@ -1720,7 +1738,7 @@ export class OpportunityGraphFactory {
1720
1738
  const candidateActor = opp.actors
1721
1739
  .find(a => a.userId !== discoveryUserId);
1722
1740
  if (!candidateActor) {
1723
- logger.verbose('[Graph:Negotiate] Skipping opportunity: no candidateActor found', {
1741
+ negotiateLog.verbose('Skipping opportunity: no candidateActor found', {
1724
1742
  opportunityId: opp.id,
1725
1743
  discoveryUserId,
1726
1744
  actors: opp.actors?.map(a => ({ userId: a.userId, role: a.role })) ?? [],
@@ -1730,7 +1748,7 @@ export class OpportunityGraphFactory {
1730
1748
  return { opp, candidateActor };
1731
1749
  })
1732
1750
  .filter((e) => e !== null);
1733
- logger.verbose('[Graph:Negotiate] Candidate filtering complete', {
1751
+ negotiateLog.verbose('Candidate filtering complete', {
1734
1752
  inputOpportunities: state.opportunities.length,
1735
1753
  outputCandidates: candidateEntries.length,
1736
1754
  });
@@ -1879,7 +1897,7 @@ export class OpportunityGraphFactory {
1879
1897
  const updated = await this.database
1880
1898
  .updateOpportunityStatus(candidate.opportunityId, 'draft')
1881
1899
  .catch((err) => {
1882
- logger.warn('[Graph:Negotiate] failed to flip opp to draft; suppressing draft-ready event', {
1900
+ negotiateLog.warn('failed to flip opp to draft; suppressing draft-ready event', {
1883
1901
  opportunityId: candidate.opportunityId,
1884
1902
  error: err,
1885
1903
  });
@@ -1941,9 +1959,9 @@ export class OpportunityGraphFactory {
1941
1959
  if (raced === NEGOTIATE_TIMER_SENTINEL) {
1942
1960
  // Floating promise is intentional — see comment above.
1943
1961
  void negotiationWork.catch((err) => {
1944
- logger.warn('[Graph:Negotiate] background negotiation failed after timer fired', { error: err });
1962
+ negotiateLog.warn('background negotiation failed after timer fired', { error: err });
1945
1963
  });
1946
- logger.warn('[Graph:Negotiate] timed out — returning partial results to caller', {
1964
+ negotiateLog.warn('timed out — returning partial results to caller', {
1947
1965
  discoveryUserId,
1948
1966
  candidateCount: candidates.length,
1949
1967
  negotiateTimeoutMs: budgetMs,
@@ -2023,7 +2041,7 @@ export class OpportunityGraphFactory {
2023
2041
  };
2024
2042
  }
2025
2043
  catch (err) {
2026
- logger.error("[Graph:Negotiate] Negotiation stage failed", { error: err });
2044
+ negotiateLog.error("Negotiation stage failed", { error: err });
2027
2045
  traceEmitter?.({ type: "graph_end", name: "Negotiation graph", durationMs: Date.now() - graphStart });
2028
2046
  return {
2029
2047
  trace: [{
@@ -2042,7 +2060,7 @@ export class OpportunityGraphFactory {
2042
2060
  */
2043
2061
  const rankingNode = withNodeTrace("opportunity-ranking", async (state) => {
2044
2062
  return timed("OpportunityGraph.ranking", async () => {
2045
- logger.verbose('[Graph:Ranking] Starting ranking', {
2063
+ rankingLog.verbose('Starting ranking', {
2046
2064
  evaluatedCount: state.evaluatedOpportunities.length,
2047
2065
  });
2048
2066
  try {
@@ -2061,7 +2079,7 @@ export class OpportunityGraphFactory {
2061
2079
  seen.add(key);
2062
2080
  return true;
2063
2081
  });
2064
- logger.verbose('[Graph:Ranking] Ranking complete', {
2082
+ rankingLog.verbose('Ranking complete', {
2065
2083
  sorted: sorted.length,
2066
2084
  afterLimit: ranked.length,
2067
2085
  afterDedup: deduplicated.length,
@@ -2070,7 +2088,7 @@ export class OpportunityGraphFactory {
2070
2088
  }
2071
2089
  catch (error) {
2072
2090
  const errMsg = error instanceof Error ? error.message : String(error);
2073
- logger.error('[Graph:Ranking] Failed', { error });
2091
+ rankingLog.error('Failed', { error });
2074
2092
  return {
2075
2093
  evaluatedOpportunities: [],
2076
2094
  error: 'Failed to rank opportunities.',
@@ -2095,7 +2113,7 @@ export class OpportunityGraphFactory {
2095
2113
  */
2096
2114
  const introValidationNode = async (state) => {
2097
2115
  return timed("OpportunityGraph.introValidation", async () => {
2098
- logger.verbose('[Graph:IntroValidation] Starting', {
2116
+ introValidationLog.verbose('Starting', {
2099
2117
  userId: state.userId,
2100
2118
  networkId: state.networkId,
2101
2119
  entitiesCount: state.introductionEntities?.length ?? 0,
@@ -2140,12 +2158,12 @@ export class OpportunityGraphFactory {
2140
2158
  if (exists) {
2141
2159
  return { error: 'An opportunity already exists between these people.' };
2142
2160
  }
2143
- logger.verbose('[Graph:IntroValidation] Validation passed');
2161
+ introValidationLog.verbose('Validation passed');
2144
2162
  return {};
2145
2163
  }
2146
2164
  catch (err) {
2147
2165
  const errMsg = err instanceof Error ? err.message : String(err);
2148
- logger.error('[Graph:IntroValidation] Failed', {
2166
+ introValidationLog.error('Failed', {
2149
2167
  userId: state.userId,
2150
2168
  networkId: state.networkId,
2151
2169
  error: err,
@@ -2182,7 +2200,7 @@ export class OpportunityGraphFactory {
2182
2200
  */
2183
2201
  const introEvaluationNode = async (state) => {
2184
2202
  return timed("OpportunityGraph.introEvaluation", async () => {
2185
- logger.verbose('[Graph:IntroEvaluation] Starting', { userId: state.userId });
2203
+ introEvaluationLog.verbose('Starting', { userId: state.userId });
2186
2204
  if (state.error) {
2187
2205
  return { evaluatedOpportunities: [], agentTimings: [] };
2188
2206
  }
@@ -2244,7 +2262,7 @@ export class OpportunityGraphFactory {
2244
2262
  _traceEmitterIntro?.({ type: "agent_end", name: "intro-evaluator", durationMs: _introErrDuration, summary: `error — ${errMsg}` });
2245
2263
  agentTimingsAccum.push({ name: 'opportunity.evaluator', durationMs: _introErrDuration });
2246
2264
  }
2247
- logger.warn('[Graph:IntroEvaluation] Evaluator or getUser failed, using fallback', { error: evalErr });
2265
+ introEvaluationLog.warn('Evaluator or getUser failed, using fallback', { error: evalErr });
2248
2266
  const fallback = buildIntroFallback(entities, state, primaryNetworkId, introducerName);
2249
2267
  reasoning = fallback.reasoning;
2250
2268
  score = fallback.score;
@@ -2282,13 +2300,13 @@ export class OpportunityGraphFactory {
2282
2300
  return timed("OpportunityGraph.persist", async () => {
2283
2301
  const startTime = Date.now();
2284
2302
  const initialStatus = resolveInitialStatus(state.trigger, state.options.initialStatus);
2285
- logger.verbose('[Graph:Persist] Starting persistence (dedup-v2)', {
2303
+ persistLog.verbose('Starting persistence (dedup-v2)', {
2286
2304
  opportunitiesToCreate: state.evaluatedOpportunities.length,
2287
2305
  trigger: state.trigger,
2288
2306
  initialStatus,
2289
2307
  });
2290
2308
  if (state.evaluatedOpportunities.length === 0) {
2291
- logger.verbose('[Graph:Persist] No opportunities to persist');
2309
+ persistLog.verbose('No opportunities to persist');
2292
2310
  return { opportunities: [] };
2293
2311
  }
2294
2312
  try {
@@ -2328,7 +2346,7 @@ export class OpportunityGraphFactory {
2328
2346
  const accepted = await this.database
2329
2347
  .findOpportunitiesByActors([dedupUserId, counterpartyUserId], { includeIntroducers: true, statuses: ['accepted'] })
2330
2348
  .catch((err) => {
2331
- logger.warn('[Graph:Persist] findOpportunitiesByActors (sibling-accept) failed', {
2349
+ persistLog.warn('findOpportunitiesByActors (sibling-accept) failed', {
2332
2350
  userId: dedupUserId,
2333
2351
  counterpartyUserId,
2334
2352
  error: err,
@@ -2343,7 +2361,7 @@ export class OpportunityGraphFactory {
2343
2361
  const indexIdForActors = state.networkId ?? evaluated.actors[0]?.networkId;
2344
2362
  let actors;
2345
2363
  let data;
2346
- logger.verbose('[Graph:Persist:PathSelect]', {
2364
+ persistPathLog.verbose('Selecting persistence path', {
2347
2365
  isIntroduction: !!state.introductionContext,
2348
2366
  stateUserId: state.userId,
2349
2367
  stateIndexId: state.networkId,
@@ -2351,7 +2369,7 @@ export class OpportunityGraphFactory {
2351
2369
  });
2352
2370
  if (state.introductionContext) {
2353
2371
  if (indexIdForActors === undefined) {
2354
- logger.warn('[Graph:Persist] Introduction path missing networkId; skipping opportunity', {
2372
+ persistLog.warn('Introduction path missing networkId; skipping opportunity', {
2355
2373
  userId: state.userId,
2356
2374
  actorsCount: evaluated.actors.length,
2357
2375
  });
@@ -2401,7 +2419,7 @@ export class OpportunityGraphFactory {
2401
2419
  }
2402
2420
  else if (state.onBehalfOfUserId) {
2403
2421
  if (indexIdForActors === undefined) {
2404
- logger.warn('[Graph:Persist] Introducer discovery path missing networkId; skipping opportunity', {
2422
+ persistLog.warn('Introducer discovery path missing networkId; skipping opportunity', {
2405
2423
  userId: state.userId,
2406
2424
  actorsCount: evaluated.actors.length,
2407
2425
  });
@@ -2440,7 +2458,7 @@ export class OpportunityGraphFactory {
2440
2458
  // initialStatus, because introductions are always chat-initiated, not background-discovered.
2441
2459
  const reactivated = await this.database.updateOpportunityStatus(existing.id, 'draft');
2442
2460
  if (reactivated) {
2443
- logger.verbose('[Graph:Persist] Reactivated opportunity (introduction path)', {
2461
+ persistLog.verbose('Reactivated opportunity (introduction path)', {
2444
2462
  opportunityId: existing.id,
2445
2463
  candidateUserId,
2446
2464
  previousStatus: existing.status,
@@ -2463,7 +2481,7 @@ export class OpportunityGraphFactory {
2463
2481
  existingOpportunityId: existing.id,
2464
2482
  existingStatus: existing.status,
2465
2483
  });
2466
- logger.verbose('[Graph:Persist] Skipping negotiating opportunity with active task (introduction path)', {
2484
+ persistLog.verbose('Skipping negotiating opportunity with active task (introduction path)', {
2467
2485
  opportunityId: existing.id,
2468
2486
  candidateUserId,
2469
2487
  taskState: priorTask.state,
@@ -2473,7 +2491,7 @@ export class OpportunityGraphFactory {
2473
2491
  }
2474
2492
  const reactivated = await this.database.updateOpportunityStatus(existing.id, 'draft');
2475
2493
  if (reactivated) {
2476
- logger.info('[Graph:Persist] Resuming orphaned negotiating opportunity (introduction path)', {
2494
+ persistLog.info('Resuming orphaned negotiating opportunity (introduction path)', {
2477
2495
  opportunityId: existing.id,
2478
2496
  candidateUserId,
2479
2497
  priorTaskState: priorTask?.state,
@@ -2486,7 +2504,7 @@ export class OpportunityGraphFactory {
2486
2504
  // Upgrade latent to draft for introduction path
2487
2505
  const upgraded = await this.database.updateOpportunityStatus(existing.id, 'draft');
2488
2506
  if (upgraded) {
2489
- logger.verbose('[Graph:Persist] Upgraded latent opportunity to draft (introduction path)', {
2507
+ persistLog.verbose('Upgraded latent opportunity to draft (introduction path)', {
2490
2508
  opportunityId: existing.id,
2491
2509
  candidateUserId,
2492
2510
  });
@@ -2502,7 +2520,7 @@ export class OpportunityGraphFactory {
2502
2520
  existingOpportunityId: existing.id,
2503
2521
  existingStatus: existing.status,
2504
2522
  });
2505
- logger.verbose('[Graph:Persist] Skipping recent duplicate (introduction path)', {
2523
+ persistLog.verbose('Skipping recent duplicate (introduction path)', {
2506
2524
  candidateUserId,
2507
2525
  existingStatus: existing.status,
2508
2526
  existingOpportunityId: existing.id,
@@ -2510,7 +2528,7 @@ export class OpportunityGraphFactory {
2510
2528
  continue;
2511
2529
  }
2512
2530
  // Else: existing opportunity is old enough, allow new opportunity creation
2513
- logger.verbose('[Graph:Persist] Allowing new opportunity; existing is outside dedup window (introduction path)', {
2531
+ persistLog.verbose('Allowing new opportunity; existing is outside dedup window (introduction path)', {
2514
2532
  candidateUserId,
2515
2533
  existingStatus: existing.status,
2516
2534
  existingOpportunityId: existing.id,
@@ -2572,7 +2590,7 @@ export class OpportunityGraphFactory {
2572
2590
  if (counterpartIdx >= 0) {
2573
2591
  actors[counterpartIdx] = { ...actors[counterpartIdx], role: 'agent' };
2574
2592
  }
2575
- logger.verbose('[Graph:Persist] Swapped discoverer from agent to patient for lifecycle visibility', {
2593
+ persistLog.verbose('Swapped discoverer from agent to patient for lifecycle visibility', {
2576
2594
  discovererId: state.userId,
2577
2595
  });
2578
2596
  }
@@ -2580,7 +2598,7 @@ export class OpportunityGraphFactory {
2580
2598
  // Index-agnostic dedup: find ANY existing opportunity between these users,
2581
2599
  // regardless of which index it was created in or whether a focused network scope is set.
2582
2600
  const candidateUserId = evaluated.actors.find((a) => a.userId !== state.userId)?.userId;
2583
- logger.verbose('[Graph:Persist:Dedup] Checking overlapping opportunities', {
2601
+ persistDedupLog.verbose('Checking overlapping opportunities', {
2584
2602
  stateUserId: state.userId,
2585
2603
  candidateUserId: candidateUserId ?? 'NONE',
2586
2604
  evaluatedActors: evaluated.actors.map(a => ({ userId: a.userId, role: a.role })),
@@ -2588,7 +2606,7 @@ export class OpportunityGraphFactory {
2588
2606
  const overlapping = candidateUserId
2589
2607
  ? await this.database.findOpportunitiesByActors([state.userId, candidateUserId], { excludeStatuses: DEDUP_SKIP_STATUSES })
2590
2608
  : [];
2591
- logger.verbose('[Graph:Persist:Dedup] findOpportunitiesByActors result', {
2609
+ persistDedupLog.verbose('findOpportunitiesByActors result', {
2592
2610
  count: overlapping.length,
2593
2611
  results: overlapping.map(o => ({ id: o.id, status: o.status, actors: o.actors?.map((a) => ({ userId: a.userId, role: a.role })) })),
2594
2612
  });
@@ -2602,7 +2620,7 @@ export class OpportunityGraphFactory {
2602
2620
  // is still in-flight for this pair, so we resume it rather than create a parallel one.
2603
2621
  const reactivated = await this.database.updateOpportunityStatus(existing.id, initialStatus);
2604
2622
  if (reactivated) {
2605
- logger.verbose('[Graph:Persist] Reactivated opportunity', {
2623
+ persistLog.verbose('Reactivated opportunity', {
2606
2624
  opportunityId: existing.id,
2607
2625
  candidateUserId,
2608
2626
  previousStatus: existing.status,
@@ -2627,7 +2645,7 @@ export class OpportunityGraphFactory {
2627
2645
  existingOpportunityId: existing.id,
2628
2646
  existingStatus: existing.status,
2629
2647
  });
2630
- logger.verbose('[Graph:Persist] Skipping negotiating opportunity with active task', {
2648
+ persistLog.verbose('Skipping negotiating opportunity with active task', {
2631
2649
  opportunityId: existing.id,
2632
2650
  candidateUserId,
2633
2651
  taskState: priorTask.state,
@@ -2638,7 +2656,7 @@ export class OpportunityGraphFactory {
2638
2656
  // Task is stale or missing — reactivate the orphaned negotiating opportunity
2639
2657
  const reactivated = await this.database.updateOpportunityStatus(existing.id, initialStatus);
2640
2658
  if (reactivated) {
2641
- logger.info('[Graph:Persist] Resuming orphaned negotiating opportunity', {
2659
+ persistLog.info('Resuming orphaned negotiating opportunity', {
2642
2660
  opportunityId: existing.id,
2643
2661
  candidateUserId,
2644
2662
  priorTaskState: priorTask?.state,
@@ -2651,7 +2669,7 @@ export class OpportunityGraphFactory {
2651
2669
  // Upgrade latent (background-discovered) to the higher-priority status (e.g. pending)
2652
2670
  const upgraded = await this.database.updateOpportunityStatus(existing.id, initialStatus);
2653
2671
  if (upgraded) {
2654
- logger.verbose('[Graph:Persist] Upgraded latent opportunity to higher-priority status', {
2672
+ persistLog.verbose('Upgraded latent opportunity to higher-priority status', {
2655
2673
  opportunityId: existing.id,
2656
2674
  candidateUserId,
2657
2675
  previousStatus: 'latent',
@@ -2670,7 +2688,7 @@ export class OpportunityGraphFactory {
2670
2688
  existingOpportunityId: existing.id,
2671
2689
  existingStatus: existing.status,
2672
2690
  });
2673
- logger.verbose('[Graph:Persist] Skipping recent duplicate; opportunity created within dedup window', {
2691
+ persistLog.verbose('Skipping recent duplicate; opportunity created within dedup window', {
2674
2692
  candidateUserId,
2675
2693
  existingStatus: existing.status,
2676
2694
  existingOpportunityId: existing.id,
@@ -2679,7 +2697,7 @@ export class OpportunityGraphFactory {
2679
2697
  continue;
2680
2698
  }
2681
2699
  // Else: existing opportunity is old enough (outside the 30-day dedup window), allow new opportunity creation
2682
- logger.verbose('[Graph:Persist] Allowing new opportunity; existing is outside dedup window', {
2700
+ persistLog.verbose('Allowing new opportunity; existing is outside dedup window', {
2683
2701
  candidateUserId,
2684
2702
  existingStatus: existing.status,
2685
2703
  existingOpportunityId: existing.id,
@@ -2723,7 +2741,7 @@ export class OpportunityGraphFactory {
2723
2741
  validateOpportunityActors(data.actors);
2724
2742
  }
2725
2743
  catch (err) {
2726
- logger.warn('[Graph:Persist] Skipping opportunity with invalid actors', {
2744
+ persistLog.warn('Skipping opportunity with invalid actors', {
2727
2745
  error: err instanceof Error ? err.message : String(err),
2728
2746
  opportunityReasoning: evaluated.reasoning?.slice(0, 80),
2729
2747
  });
@@ -2737,7 +2755,7 @@ export class OpportunityGraphFactory {
2737
2755
  items: itemsToPersist,
2738
2756
  });
2739
2757
  const allOpportunities = [...reactivatedOpportunities, ...createdList];
2740
- logger.verbose('[Graph:Persist] Persistence complete', {
2758
+ persistLog.verbose('Persistence complete', {
2741
2759
  created: createdList.length,
2742
2760
  reactivated: reactivatedOpportunities.length,
2743
2761
  existingBetweenActorsCount: existingBetweenActors.length,
@@ -2763,7 +2781,7 @@ export class OpportunityGraphFactory {
2763
2781
  }
2764
2782
  catch (error) {
2765
2783
  const errMsg = error instanceof Error ? error.message : String(error);
2766
- logger.error('[Graph:Persist] Failed', { error });
2784
+ persistLog.error('Failed', { error });
2767
2785
  return {
2768
2786
  opportunities: [],
2769
2787
  existingBetweenActors: [],
@@ -2792,7 +2810,7 @@ export class OpportunityGraphFactory {
2792
2810
  */
2793
2811
  const readNode = async (state) => {
2794
2812
  return timed("OpportunityGraph.read", async () => {
2795
- logger.verbose('[Graph:Read] Listing opportunities', {
2813
+ readLog.verbose('Listing opportunities', {
2796
2814
  userId: state.userId,
2797
2815
  networkId: state.networkId,
2798
2816
  });
@@ -2900,7 +2918,7 @@ export class OpportunityGraphFactory {
2900
2918
  };
2901
2919
  }
2902
2920
  catch (err) {
2903
- logger.error('[Graph:Read] Failed', { error: err });
2921
+ readLog.error('Failed', { error: err });
2904
2922
  return {
2905
2923
  readResult: { count: 0, opportunities: [], message: 'Failed to list opportunities.' },
2906
2924
  };
@@ -2916,7 +2934,7 @@ export class OpportunityGraphFactory {
2916
2934
  */
2917
2935
  const updateNode = async (state) => {
2918
2936
  return timed("OpportunityGraph.update", async () => {
2919
- logger.verbose('[Graph:Update] Updating opportunity status', {
2937
+ updateLog.verbose('Updating opportunity status', {
2920
2938
  userId: state.userId,
2921
2939
  opportunityId: state.opportunityId,
2922
2940
  newStatus: state.newStatus,
@@ -2972,7 +2990,7 @@ export class OpportunityGraphFactory {
2972
2990
  };
2973
2991
  }
2974
2992
  catch (err) {
2975
- logger.error('[Graph:Update] Failed', { error: err });
2993
+ updateLog.error('Failed', { error: err });
2976
2994
  return { mutationResult: { success: false, error: 'Failed to update opportunity.' } };
2977
2995
  }
2978
2996
  });
@@ -2982,7 +3000,7 @@ export class OpportunityGraphFactory {
2982
3000
  */
2983
3001
  const deleteNode = async (state) => {
2984
3002
  return timed("OpportunityGraph.delete", async () => {
2985
- logger.verbose('[Graph:Delete] Expiring opportunity', {
3003
+ deleteLog.verbose('Expiring opportunity', {
2986
3004
  userId: state.userId,
2987
3005
  opportunityId: state.opportunityId,
2988
3006
  });
@@ -3008,7 +3026,7 @@ export class OpportunityGraphFactory {
3008
3026
  };
3009
3027
  }
3010
3028
  catch (err) {
3011
- logger.error('[Graph:Delete] Failed', { error: err });
3029
+ deleteLog.error('Failed', { error: err });
3012
3030
  return { mutationResult: { success: false, error: 'Failed to delete opportunity.' } };
3013
3031
  }
3014
3032
  });
@@ -3018,7 +3036,7 @@ export class OpportunityGraphFactory {
3018
3036
  */
3019
3037
  const sendNode = async (state) => {
3020
3038
  return timed("OpportunityGraph.send", async () => {
3021
- logger.verbose('[Graph:Send] Sending opportunity', {
3039
+ sendLog.verbose('Sending opportunity', {
3022
3040
  userId: state.userId,
3023
3041
  opportunityId: state.opportunityId,
3024
3042
  });
@@ -3081,7 +3099,7 @@ export class OpportunityGraphFactory {
3081
3099
  };
3082
3100
  }
3083
3101
  catch (err) {
3084
- logger.error('[Graph:Send] Failed', { error: err });
3102
+ sendLog.error('Failed', { error: err });
3085
3103
  return { mutationResult: { success: false, error: 'Failed to send opportunity.' } };
3086
3104
  }
3087
3105
  });
@@ -3094,7 +3112,7 @@ export class OpportunityGraphFactory {
3094
3112
  if (!state.opportunityId)
3095
3113
  return {};
3096
3114
  if (!this.negotiationGraph) {
3097
- logger.warn('[Graph:NegotiateExisting] No negotiationGraph wired; skipping', {
3115
+ negotiateExistingLog.warn('No negotiationGraph wired; skipping', {
3098
3116
  opportunityId: state.opportunityId,
3099
3117
  });
3100
3118
  return {};
@@ -3102,7 +3120,7 @@ export class OpportunityGraphFactory {
3102
3120
  try {
3103
3121
  const opp = await this.database.getOpportunity(state.opportunityId);
3104
3122
  if (!opp) {
3105
- logger.warn('[Graph:NegotiateExisting] Opportunity not found', { opportunityId: state.opportunityId });
3123
+ negotiateExistingLog.warn('Opportunity not found', { opportunityId: state.opportunityId });
3106
3124
  return {};
3107
3125
  }
3108
3126
  const actors = opp.actors;
@@ -3111,13 +3129,13 @@ export class OpportunityGraphFactory {
3111
3129
  const sourceActor = nonIntroducerActors.find(a => a.role === 'patient' || a.role === 'party')
3112
3130
  ?? nonIntroducerActors[0];
3113
3131
  if (!sourceActor) {
3114
- logger.warn('[Graph:NegotiateExisting] No source actor found', { opportunityId: state.opportunityId });
3132
+ negotiateExistingLog.warn('No source actor found', { opportunityId: state.opportunityId });
3115
3133
  return {};
3116
3134
  }
3117
3135
  // Find the candidateActor: non-introducer that is NOT the sourceActor
3118
3136
  const candidateActor = nonIntroducerActors.find(a => a.userId !== sourceActor.userId);
3119
3137
  if (!candidateActor) {
3120
- logger.warn('[Graph:NegotiateExisting] No candidate actor found', { opportunityId: state.opportunityId });
3138
+ negotiateExistingLog.warn('No candidate actor found', { opportunityId: state.opportunityId });
3121
3139
  return {};
3122
3140
  }
3123
3141
  // Load user data for both actors in parallel
@@ -3181,17 +3199,17 @@ export class OpportunityGraphFactory {
3181
3199
  if (acceptedResults.length > 0 && this.queueNotification) {
3182
3200
  for (const actor of nonIntroducerActors) {
3183
3201
  await this.queueNotification(opp.id, actor.userId, 'high').catch((err) => {
3184
- logger.warn('[Graph:NegotiateExisting] Failed to queue notification', { actorId: actor.userId, error: err });
3202
+ negotiateExistingLog.warn('Failed to queue notification', { actorId: actor.userId, error: err });
3185
3203
  });
3186
3204
  }
3187
3205
  }
3188
- logger.info('[Graph:NegotiateExisting] Negotiation complete', {
3206
+ negotiateExistingLog.info('Negotiation complete', {
3189
3207
  opportunityId: opp.id,
3190
3208
  accepted: acceptedResults.length > 0,
3191
3209
  });
3192
3210
  }
3193
3211
  catch (err) {
3194
- logger.error('[Graph:NegotiateExisting] Failed', { opportunityId: state.opportunityId, error: err });
3212
+ negotiateExistingLog.error('Failed', { opportunityId: state.opportunityId, error: err });
3195
3213
  return { error: `Failed to load opportunity: ${err instanceof Error ? err.message : String(err)}` };
3196
3214
  }
3197
3215
  return {};
@@ -3265,17 +3283,17 @@ export class OpportunityGraphFactory {
3265
3283
  */
3266
3284
  const shouldContinueAfterPrep = (state) => {
3267
3285
  if (state.error) {
3268
- logger.verbose('[Graph:Routing] Error in prep - ending early');
3286
+ routingLog.verbose('Error in prep - ending early');
3269
3287
  return END;
3270
3288
  }
3271
3289
  // Continuation mode: skip scope/resolve/discovery, go straight to evaluation
3272
3290
  if (state.operationMode === 'continue_discovery') {
3273
- logger.verbose('[Graph:Routing] Continue discovery → skipping to evaluation', {
3291
+ routingLog.verbose('Continue discovery → skipping to evaluation', {
3274
3292
  candidatesLoaded: state.candidates.length,
3275
3293
  });
3276
3294
  return 'evaluation';
3277
3295
  }
3278
- logger.verbose('[Graph:Routing] Continuing to scope');
3296
+ routingLog.verbose('Continuing to scope');
3279
3297
  return 'scope';
3280
3298
  };
3281
3299
  /**
@@ -3283,10 +3301,10 @@ export class OpportunityGraphFactory {
3283
3301
  */
3284
3302
  const shouldContinueAfterScope = (state) => {
3285
3303
  if (state.error || state.targetNetworks.length === 0) {
3286
- logger.verbose('[Graph:Routing] No target indexes - ending early');
3304
+ routingLog.verbose('No target indexes - ending early');
3287
3305
  return END;
3288
3306
  }
3289
- logger.verbose('[Graph:Routing] Continuing to resolve');
3307
+ routingLog.verbose('Continuing to resolve');
3290
3308
  return 'resolve';
3291
3309
  };
3292
3310
  /**
@@ -3294,7 +3312,7 @@ export class OpportunityGraphFactory {
3294
3312
  */
3295
3313
  const shouldContinueAfterDiscovery = (state) => {
3296
3314
  if (state.createIntentSuggested) {
3297
- logger.verbose('[Graph:Routing] Create-intent suggested - ending for tool signal');
3315
+ routingLog.verbose('Create-intent suggested - ending for tool signal');
3298
3316
  return END;
3299
3317
  }
3300
3318
  return 'evaluation';
@@ -3304,7 +3322,7 @@ export class OpportunityGraphFactory {
3304
3322
  */
3305
3323
  const routeAfterIntroValidation = (state) => {
3306
3324
  if (state.error) {
3307
- logger.verbose('[Graph:Routing] Intro validation error - ending early');
3325
+ routingLog.verbose('Intro validation error - ending early');
3308
3326
  return END;
3309
3327
  }
3310
3328
  return 'intro_evaluation';