@indexnetwork/protocol 65.0.0 → 66.0.0-rc.608.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.
@@ -50,8 +50,8 @@ export type RadarGraphInvokeResult = {
50
50
  export declare const DEFAULT_RADAR_STATUSES: OpportunityStatus[];
51
51
  /** Full status enumeration. Pass this to `RadarGraphInvokeInput.statuses` to restore pre-Issue-3 (unfiltered) behavior. */
52
52
  export declare const ALL_OPPORTUNITY_STATUSES: OpportunityStatus[];
53
- /** Pure cache policy for presenter cards; degraded current-request copy retries later. */
54
- export declare function isRadarPresentationCacheable(card: Pick<RadarCardItem, 'presentationPending' | '_presentationFallback' | 'name'>, status: OpportunityStatus | undefined): boolean;
53
+ /** Pure cache policy for presenter cards. */
54
+ export declare function isRadarPresentationCacheable(card: Pick<RadarCardItem, 'presentationPending' | 'name'>, status: OpportunityStatus | undefined): boolean;
55
55
  /**
56
56
  * Strip leading narrator name from remark when the UI already prepends "Name: " to the chip.
57
57
  * Avoids duplication like "Yankı Ekin Yüksel: Yankı Ekin Yüksel introduced you two..."
@@ -16,7 +16,6 @@ import { OpportunityPresenter, gatherPresenterContext } from '../opportunity.pre
16
16
  import { loadNegotiationContext } from '../negotiation-context.loader.js';
17
17
  import { canUserSeeOpportunity, isActionableForViewer, selectByComposition } from '../opportunity.utils.js';
18
18
  import { getPrimaryActionLabel, SECONDARY_ACTION_LABEL } from '../opportunity.labels.js';
19
- import { safeFallbackSummary } from '../opportunity.presentation.js';
20
19
  import { buildRadarCardPresentationCacheKey } from '../opportunity.presentation.js';
21
20
  import { protocolLogger } from '../../shared/observability/protocol.logger.js';
22
21
  import { timed } from '../../shared/observability/performance.js';
@@ -41,14 +40,12 @@ const OPPORTUNITY_STATUS_REGISTRY = {
41
40
  /** Full status enumeration. Pass this to `RadarGraphInvokeInput.statuses` to restore pre-Issue-3 (unfiltered) behavior. */
42
41
  export const ALL_OPPORTUNITY_STATUSES = Object.keys(OPPORTUNITY_STATUS_REGISTRY);
43
42
  const PRESENTATION_CONCURRENCY = 50;
44
- const MAX_REASONING_SNIPPET_LENGTH = 240;
45
43
  const RADAR_CACHE_TTL = 24 * 60 * 60; // 24 hours in seconds
46
- /** Pure cache policy for presenter cards; degraded current-request copy retries later. */
44
+ /** Pure cache policy for presenter cards. */
47
45
  export function isRadarPresentationCacheable(card, status) {
48
46
  return Boolean(status &&
49
47
  status !== 'negotiating' &&
50
48
  !card.presentationPending &&
51
- !card._presentationFallback &&
52
49
  card.name &&
53
50
  card.name !== 'Unknown');
54
51
  }
@@ -383,15 +380,6 @@ export async function generateCardTextNode(state, deps) {
383
380
  return null;
384
381
  }
385
382
  const userAvatar = otherUser?.avatar ?? null;
386
- // Shared sanitization standard (UUID strip, viewer-centric rewrite,
387
- // boundary truncation) — raw reasoning must never render verbatim.
388
- const reasoningSnippet = safeFallbackSummary(typeof opportunity.interpretation?.reasoning === 'string'
389
- ? opportunity.interpretation.reasoning
390
- : '', {
391
- counterpartName: userName !== 'Unknown' ? userName : undefined,
392
- maxChars: MAX_REASONING_SNIPPET_LENGTH,
393
- emptyText: 'A promising connection.',
394
- });
395
383
  // Skeleton presentation: return an identity-only card without the
396
384
  // deps.presenter LLM or negotiation-context load. Name resolution and
397
385
  // the unresolvable-counterpart drop above still apply, so the card
@@ -413,22 +401,6 @@ export async function generateCardTextNode(state, deps) {
413
401
  _cardIndex: cardIndex,
414
402
  };
415
403
  }
416
- const fallbackCard = (outcomeReasoning) => ({
417
- opportunityId: opportunity.id,
418
- status: opportunity.status,
419
- userId: otherActor?.userId ?? '',
420
- name: userName,
421
- avatar: userAvatar,
422
- mainText: outcomeReasoning ?? reasoningSnippet,
423
- cta: 'Take a look and decide whether to reach out.',
424
- primaryActionLabel: getPrimaryActionLabel(viewerRole),
425
- secondaryActionLabel: SECONDARY_ACTION_LABEL,
426
- mutualIntentsLabel: 'Shared interests',
427
- narratorChip: { name: 'Index', text: 'Worth a look.' },
428
- viewerRole,
429
- _presentationFallback: true,
430
- _cardIndex: cardIndex,
431
- });
432
404
  try {
433
405
  const [ctx, negotiationContext] = await Promise.all([
434
406
  gatherPresenterContext(db, opportunity, state.userId, otherActor?.userId, state.scopeId),
@@ -447,9 +419,6 @@ export async function generateCardTextNode(state, deps) {
447
419
  const _presenterDuration = Date.now() - presenterStart;
448
420
  agentTimingsAccum.push({ name: 'opportunity.presenter', durationMs: _presenterDuration });
449
421
  _traceEmitterPresenter?.({ type: "agent_end", name: "opportunity-presenter", durationMs: _presenterDuration, summary: `Presented: ${userName}` });
450
- if (presentation.isFallback) {
451
- return fallbackCard();
452
- }
453
422
  // Every card is system-discovered now: one narrator.
454
423
  const narratorChip = { name: 'Index', text: presentation.narratorRemark };
455
424
  return {
@@ -471,7 +440,7 @@ export async function generateCardTextNode(state, deps) {
471
440
  }
472
441
  catch (e) {
473
442
  logger.warn('RadarGraph presenter failed for opportunity', { opportunityId: opportunity.id, error: e });
474
- return fallbackCard();
443
+ return null;
475
444
  }
476
445
  }));
477
446
  cards.push(...chunkCards.filter((c) => c !== null));
@@ -493,7 +462,7 @@ export async function cachePresenterResultsNode(state, deps) {
493
462
  try {
494
463
  await Promise.all(newCards.map((card) => {
495
464
  const status = statusById.get(card.opportunityId);
496
- // Negotiating, skeleton, fallback, and unresolved-name cards are
465
+ // Negotiating, skeleton, and unresolved-name cards are
497
466
  // safe for the current response but must not become 24h entries.
498
467
  if (!status || !isRadarPresentationCacheable(card, status))
499
468
  return Promise.resolve();
@@ -527,7 +496,7 @@ export async function normalizeItemsNode(state) {
527
496
  normalizeItemsLog.verbose('entry', { cardsLength: state.cards.length });
528
497
  const createdAtById = new Map(state.opportunities.map((opportunity) => [opportunity.id, opportunity.createdAt.toISOString()]));
529
498
  const items = state.cards.map((card) => {
530
- const { _cardIndex, _presentationFallback, ...rest } = card;
499
+ const { _cardIndex, ...rest } = card;
531
500
  return { ...rest, createdAt: createdAtById.get(card.opportunityId) };
532
501
  });
533
502
  const meta = { totalOpportunities: state.opportunities.length };
@@ -35,13 +35,11 @@ export interface RadarCardItem {
35
35
  * full view. Skeleton cards are never written to the presenter cache.
36
36
  */
37
37
  presentationPending?: boolean;
38
- /** Internal marker: safe deterministic fallback rendered, but must not be cached. */
39
- _presentationFallback?: boolean;
40
38
  /** Internal: original position in the loaded opportunity list, for stable ordering. */
41
39
  _cardIndex: number;
42
40
  }
43
41
  /** Card item as returned in API responses (no internal fields). */
44
- export type RadarResponseItem = Omit<RadarCardItem, '_cardIndex' | '_presentationFallback'>;
42
+ export type RadarResponseItem = Omit<RadarCardItem, '_cardIndex'>;
45
43
  /**
46
44
  * Radar Graph State (Annotation-based).
47
45
  * Flow: loadOpportunities → checkPresenterCache → [generateCardText if misses]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indexnetwork/protocol",
3
- "version": "65.0.0",
3
+ "version": "66.0.0-rc.608.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -1,24 +0,0 @@
1
- /**
2
- * Deterministic guard for unsupported person-affiliation and presence claims.
3
- *
4
- * Opportunity presentation contracts currently do not carry typed provenance
5
- * proving attendance, membership, residence, or shared presence. The guard
6
- * therefore fails closed: a sentence making one of those claims is rejected
7
- * rather than loosely "grounded" against network/context text.
8
- *
9
- * The patterns are deliberately phrase-based. They target factual claims such
10
- * as "Alice is a member of..." while leaving generic domain phrases such as
11
- * "membership model" and "team members" alone. This is not a general factuality
12
- * checker and does not attempt semantic inference beyond the listed claim
13
- * families.
14
- */
15
- /** Returns true when text contains an unsupported affiliation/presence claim. */
16
- export declare function hasUnsupportedOpportunityClaim(text: string | null | undefined): boolean;
17
- /** Returns true when one sentence contains an unsupported claim family. */
18
- export declare function isUnsupportedOpportunityClaimSentence(sentence: string): boolean;
19
- /**
20
- * Removes complete sentences containing unsupported claims and preserves the
21
- * remaining sentence order. An all-unsafe input becomes an empty string so the
22
- * caller can apply a field-specific deterministic default.
23
- */
24
- export declare function stripUnsupportedOpportunityClaims(text: string | null | undefined): string;
@@ -1,88 +0,0 @@
1
- /**
2
- * Deterministic guard for unsupported person-affiliation and presence claims.
3
- *
4
- * Opportunity presentation contracts currently do not carry typed provenance
5
- * proving attendance, membership, residence, or shared presence. The guard
6
- * therefore fails closed: a sentence making one of those claims is rejected
7
- * rather than loosely "grounded" against network/context text.
8
- *
9
- * The patterns are deliberately phrase-based. They target factual claims such
10
- * as "Alice is a member of..." while leaving generic domain phrases such as
11
- * "membership model" and "team members" alone. This is not a general factuality
12
- * checker and does not attempt semantic inference beyond the listed claim
13
- * families.
14
- */
15
- const UNSUPPORTED_CLAIM_PATTERNS = [
16
- // Attendance and co-attendance claims. Relational grammar avoids product
17
- // phrases such as "attendee management".
18
- /\b(?:co[-\s]?attendance|co[-\s]?attendee(?:s)?|co[-\s]?attend(?:ed|ing)?|(?:another|fellow)\s+(?:(?:event|session|conference|summit|gathering|meetup)\s+)?attendees?)\b/i,
19
- /\b(?:is|are|was|were|will be|has been|have been|as)\s+(?:an?\s+)?attendees?\b/i,
20
- /\b(?:a|an|this|that)\s+attendee\s+(?:of|at)\b/i,
21
- /\b(?:will\s+|plans?\s+to\s+)?attend(?:ed|ing)?\s+(?!to\b)(?:(?:at|in)\s+)?(?:the\s+)?[\p{L}\p{N}&'’.-]+\b/iu,
22
- /\b(?:is|are|was|were|will be)\s+going\s+to\s+(?:the\s+)?(?:event|session|conference|summit|gathering|meetup|[A-Z][\p{L}\p{N}&'’.-]*)\b/u,
23
- /\b(?:[Pp]articipat(?:ed|ing)|[Pp]articipants?)\b(?=.{0,40}\b(?:in|at)\s+(?:the\s+)?(?:event|session|conference|summit|gathering|meetup|[A-Z][\p{L}\p{N}&'’.-]*))/u,
24
- /\b(?:[Ww]ent\s+to|[Tt]ook\s+part\s+in|(?:[Ww]as|[Ww]ere|[Ii]s|[Aa]re)\s+present\s+at)\s+(?:the\s+)?(?:event|session|conference|summit|gathering|meetup|[A-Z][\p{L}\p{N}&'’.-]*)\b/u,
25
- /\b(?:session\s+attendance|attendance\s+(?:at|in)\s+(?:the\s+)?(?:event|session|conference|summit|gathering|meetup))\b/i,
26
- // Shared event/session/place/time claims, including "both were at ...".
27
- /\b(?:same|the same)\s+(?:event|session|place|location|venue|time)\b/i,
28
- /\b(?:share|shared|sharing)\s+(?:an?\s+|the\s+)?(?:event|session|workshop|conference|summit|gathering|meetup|place|location|venue|time)\b/i,
29
- /\bboth\s+(?:were|are|will be|have been)\s+(?:at|in|during)\b/i,
30
- /\b(?:were|are|will be|have been)\s+both\s+(?:at|in|during)\b/i,
31
- /\b(?:will|would|are|were)\s+both\s+be?\s*(?:at|in|during)\b/i,
32
- /\bboth\b.{0,80}\b(?:attend(?:ed|ing)?|participat(?:e|ed|ing)|met|meet|meeting|stayed|stay)\b.{0,60}\b(?:event|session|place|location|venue|time)\b/i,
33
- // Factual membership/affiliation claims. Generic descriptions of product
34
- // users ("members of cooperatives") and "team members" stay untouched.
35
- /\b(?:is|are|was|were|be|being|been|became|become|as)\s+(?:an?\s+)?(?:fellow\s+)?members?\s+(?:of|in)\b/i,
36
- /\b(?:another|fellow)\s+members?\b/i,
37
- /\b(?:is|are|was|were|be|being|been|as)\s+(?:an?\s+)?(?:community|network|event)\s+members?\b/i,
38
- /\b(?:a|an|this|that)\s+(?:fellow\s+)?member\s+(?:of|in)\b/i,
39
- /\b(?:is|are|was|were|be|being|been)\s+(?:an?\s+)?part\s+of\s+(?:the\s+)?[^.!?]{0,60}\b(?:community|network|event)\b/i,
40
- /\bfellow\s+members?\s+(?:of|in)\b/i,
41
- /\b(?:a|an)\s+(?:[A-Z][\p{L}\p{N}&'’.-]*\s+){1,6}(?:community\s+|network\s+)?member\b/u,
42
- /\b(?:[Bb]elongs?|[Bb]elonged)\s+to\s+(?:the\s+)?(?:[Nn]etwork|[Cc]ommunity|[Ee]vent|(?:[A-Z][\p{L}\p{N}&'’.-]*\s+){1,5}[A-Z][\p{L}\p{N}&'’.-]*)\b/u,
43
- /\b[Jj]oined\s+(?:the\s+)?(?:[Nn]etwork|[Cc]ommunity|[Ee]vent|(?:[A-Z][\p{L}\p{N}&'’.-]*\s+){1,5}[A-Z][\p{L}\p{N}&'’.-]*)\b/u,
44
- /\b[Aa]ffiliated\s+with\s+(?:the\s+)?(?:[Nn]etwork|[Cc]ommunity|[Ee]vent|[A-Z][\p{L}\p{N}&'’.-]*)\b/u,
45
- // Residence/co-residence claims. Require person-claim grammar so generic
46
- // audience descriptions such as "tools for residents of Berlin" survive.
47
- /\b(?:is|are|was|were|be|being|been|as)\s+(?:an?\s+)?(?:local\s+|long[-\s]?time\s+|co[-\s]?)?residents?\b/i,
48
- /\bco[-\s]?(?:reside|resides|resided|residing)\b/i,
49
- /\b(?:another|fellow)\s+residents?\b/i,
50
- /\b(?:a|an|this|that)\s+(?:co[-\s]?)?resident\s+(?:of|in)\b/i,
51
- /\b(?:a|an)\s+(?:[A-Z][\p{L}\p{N}&'’.-]*\s+){1,6}(?:co[-\s]?)?resident\b/u,
52
- /\b(?:[Hh]e|[Ss]he|[Tt]hey|[A-Z][\p{L}'’.-]+)\s+(?:reside|resides|resided|residing|live|lives|lived|living|(?:is|are|was|were)\s+based)\s+in\b/u,
53
- /\b(?:[Hh]e|[Ss]he|[Tt]hey|[A-Z][\p{L}'’.-]+)\s+calls?\s+[A-Z][\p{L}\p{N}&'’.-]*(?:\s+[A-Z][\p{L}\p{N}&'’.-]*){0,5}\s+home\b/u,
54
- // Relationship claims inferred from shared network/event placement.
55
- /\b(?:know|knows|knew|met|meet)\b.{0,60}\b(?:through|from|at)\s+(?:the\s+)?(?:network|community|event|session)\b/i,
56
- /\bcrossed\s+paths\s+(?:at|during)\b/i,
57
- ];
58
- /** Returns true when text contains an unsupported affiliation/presence claim. */
59
- export function hasUnsupportedOpportunityClaim(text) {
60
- if (!text?.trim())
61
- return false;
62
- return splitClaimSentences(text).some(isUnsupportedOpportunityClaimSentence);
63
- }
64
- /** Returns true when one sentence contains an unsupported claim family. */
65
- export function isUnsupportedOpportunityClaimSentence(sentence) {
66
- return UNSUPPORTED_CLAIM_PATTERNS.some((pattern) => pattern.test(sentence));
67
- }
68
- /**
69
- * Removes complete sentences containing unsupported claims and preserves the
70
- * remaining sentence order. An all-unsafe input becomes an empty string so the
71
- * caller can apply a field-specific deterministic default.
72
- */
73
- export function stripUnsupportedOpportunityClaims(text) {
74
- if (!text?.trim())
75
- return "";
76
- return splitClaimSentences(text)
77
- .filter((sentence) => !isUnsupportedOpportunityClaimSentence(sentence))
78
- .join(" ")
79
- .replace(/\s+/g, " ")
80
- .trim();
81
- }
82
- function splitClaimSentences(text) {
83
- return text
84
- .trim()
85
- .split(/(?<=[.!?])\s+|\n+/)
86
- .map((sentence) => sentence.trim())
87
- .filter(Boolean);
88
- }