@indexnetwork/protocol 4.9.0-rc.348.1 → 4.10.0-rc.349.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 (26) hide show
  1. package/dist/index.d.ts +4 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +2 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/opportunity/discriminator/discriminator.adjustments.d.ts +52 -0
  6. package/dist/opportunity/discriminator/discriminator.adjustments.d.ts.map +1 -0
  7. package/dist/opportunity/discriminator/discriminator.adjustments.js +97 -0
  8. package/dist/opportunity/discriminator/discriminator.adjustments.js.map +1 -0
  9. package/dist/opportunity/discriminator/discriminator.env.d.ts +25 -0
  10. package/dist/opportunity/discriminator/discriminator.env.d.ts.map +1 -1
  11. package/dist/opportunity/discriminator/discriminator.env.js +25 -0
  12. package/dist/opportunity/discriminator/discriminator.env.js.map +1 -1
  13. package/dist/opportunity/discriminator/discriminator.question.d.ts.map +1 -1
  14. package/dist/opportunity/discriminator/discriminator.question.js +14 -5
  15. package/dist/opportunity/discriminator/discriminator.question.js.map +1 -1
  16. package/dist/opportunity/feed/feed.graph.d.ts.map +1 -1
  17. package/dist/opportunity/feed/feed.graph.js +56 -13
  18. package/dist/opportunity/feed/feed.graph.js.map +1 -1
  19. package/dist/opportunity/feed/feed.state.d.ts +2 -0
  20. package/dist/opportunity/feed/feed.state.d.ts.map +1 -1
  21. package/dist/opportunity/feed/feed.state.js.map +1 -1
  22. package/dist/opportunity/opportunity.presenter.d.ts +6 -0
  23. package/dist/opportunity/opportunity.presenter.d.ts.map +1 -1
  24. package/dist/opportunity/opportunity.presenter.js +12 -3
  25. package/dist/opportunity/opportunity.presenter.js.map +1 -1
  26. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"discriminator.question.js","sourceRoot":"/","sources":["opportunity/discriminator/discriminator.question.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,gCAAgC,EAAE,gCAAgC,EAAE,+BAA+B,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAGpK,+EAA+E;AAC/E,MAAM,CAAC,MAAM,iBAAiB,GAAG,aAAa,CAAC;AAE/C,mFAAmF;AACnF,MAAM,eAAe,GAAG,CAAC,CAAC;AAE1B,sDAAsD;AACtD,MAAM,mBAAmB,GAAG,SAAS,CAAC;AAEtC;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,CAAsB;IAC5D,MAAM,UAAU,GAA2B,EAAE,CAAC;IAC9C,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,KAAK;QAAE,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjD,MAAM,WAAW,GAAmD,EAAE,CAAC;IACvE,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;QAC9B,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,QAAQ;YAAE,SAAS;QAC7C,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,UAAU,CAAC;YAAE,SAAS;QACtC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxB,WAAW,CAAC,IAAI,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO;QACL,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,UAAU;QACV,GAAG,EAAE,CAAC,CAAC,GAAG;QACV,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,WAAW;KACZ,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,4BAA4B,CAAC,cAAqC;IAChF,OAAO,cAAc;SAClB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,qBAAqB,IAAI,CAAC,CAAC,YAAY,IAAI,+BAA+B,CAAC;SAClG,KAAK,CAAC,CAAC,EAAE,gCAAgC,CAAC,CAAC;AAChD,CAAC;AAED,sDAAsD;AACtD,SAAS,SAAS,CAAC,IAAY;IAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACvC,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACnD,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,IAAY;IAClC,OAAO,IAAI;SACR,OAAO,CAAC,0CAA0C,EAAE,CAAC,CAAC,EAAE,IAAY,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC;SACrG,OAAO,CAAC,YAAY,EAAE,SAAS,CAAC;SAChC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC;SACxB,OAAO,CAAC,UAAU,EAAE,MAAM,CAAC;QAC5B,2EAA2E;QAC3E,wCAAwC;SACvC,OAAO,CAAC,4CAA4C,EAAE,SAAS,CAAC;SAChE,OAAO,CAAC,wCAAwC,EAAE,QAAQ,CAAC;SAC3D,OAAO,CAAC,qCAAqC,EAAE,MAAM,CAAC;SACtD,OAAO,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;AACzD,CAAC;AAED;;;;GAIG;AACH,SAAS,YAAY,CAAC,IAAY,EAAE,IAAY;IAC9C,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACrC,OAAO,IAAI;SACR,WAAW,EAAE;SACb,KAAK,CAAC,aAAa,CAAC;SACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;SAC3B,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AACxC,CAAC;AAED,yEAAyE;AACzE,SAAS,QAAQ,CAAC,YAAoB,EAAE,KAAe;IACrD,IAAI,CAAC,GAAG,cAAc,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IACjE,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACtE,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACrC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3C,CAAC,GAAG,4BAA4B,IAAI,OAAO,IAAI,EAAE,CAAC;IACpD,CAAC;IACD,iFAAiF;IACjF,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC;IACvD,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACzB,CAAC;AA0BD;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAkC;IACvE,MAAM,EAAE,aAAa,EAAE,CAAC,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAC7C,IAAI,QAAQ,GAAG,gCAAgC;QAAE,OAAO,IAAI,CAAC;IAC7D,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAE1D,4EAA4E;IAC5E,2EAA2E;IAC3E,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;IACpE,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC;QACjC,CAAC,CAAC,YAAY,QAAQ,qBAAqB,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG;QACrG,CAAC,CAAC,YAAY,QAAQ,8BAA8B,CAAC;IAEvD,MAAM,WAAW,GAAqB,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC3D,KAAK,EAAE,SAAS,CAAC,IAAI,CAAC;QACtB,WAAW,EAAE,GAAG,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,QAAQ,gCAAgC;KAC5F,CAAC,CAAC,CAAC;IACJ,MAAM,OAAO,GAAqB;QAChC,GAAG,WAAW;QACd;YACE,KAAK,EAAE,iBAAiB;YACxB,WAAW,EAAE,0CAA0C;SACxD;KACF,CAAC;IAEF,OAAO;QACL,OAAO,EAAE;YACP,KAAK,EAAE,mBAAmB;YAC1B,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC;YACzC,OAAO;YACP,WAAW,EAAE,KAAK;YAClB,QAAQ;SACT;QACD,IAAI,EAAE;YACJ,QAAQ;YACR,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9C,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpE,aAAa,EAAE,CAAC;YAChB,UAAU,EAAE,KAAK,CAAC,UAAU;SAC7B;KACF,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Deterministic pool_discovery question synthesis (IND-418).\n *\n * A mined discriminator already carries everything a question needs: a label,\n * a question seed, 2–3 sides, and verified per-candidate assignments. This\n * module turns the top discriminator into a `Question` payload + server-side\n * pool snapshot with ZERO generation-time LLM calls — the phrasing was\n * produced (and evidence-verified) at mining time, so synthesis is pure,\n * auditable, and cheap to re-run for interview-mode chaining.\n */\nimport type { Question, QuestionOption, QuestionPoolDiscriminator, QuestionPoolSnapshot } from \"../../shared/schemas/question.schema.js\";\nimport { POOL_DISCRIMINATOR_MIN_POOL_SIZE, POOL_QUESTION_MAX_DISCRIMINATORS, POOL_QUESTION_MIN_EVIDENCE_RATE, POOL_QUESTION_MIN_VOI } from \"./discriminator.env.js\";\nimport type { ScoredDiscriminator } from \"./discriminator.types.js\";\n\n/** Fixed option appended to every pool question — the no-preference escape. */\nexport const BOTH_MATTER_LABEL = \"Both matter\";\n\n/** Max words in a chip-style option label (prototype voice: terse, glanceable). */\nconst MAX_LABEL_WORDS = 5;\n\n/** Question title (≤12 chars, per QuestionSchema). */\nconst POOL_QUESTION_TITLE = \"Matches\";\n\n/**\n * Converts a scored discriminator into the compact snapshot form stored on\n * the question row (verified assignments only; unknowns dropped).\n */\nexport function toQuestionDiscriminator(d: ScoredDiscriminator): QuestionPoolDiscriminator {\n const sideCounts: Record<string, number> = {};\n for (const side of d.sides) sideCounts[side] = 0;\n const assignments: Array<{ opportunityId: string; side: string }> = [];\n for (const a of d.assignments) {\n if (a.side === null || !a.verified) continue;\n if (!(a.side in sideCounts)) continue;\n sideCounts[a.side] += 1;\n assignments.push({ opportunityId: a.id, side: a.side });\n }\n return {\n label: d.label,\n questionSeed: d.questionSeed,\n sides: d.sides,\n sideCounts,\n voi: d.voi,\n evidenceRate: d.evidenceRate,\n assignments,\n };\n}\n\n/**\n * Filters a mining pass down to question-eligible discriminators:\n * VoI ≥ {@link POOL_QUESTION_MIN_VOI}, evidenceRate ≥\n * {@link POOL_QUESTION_MIN_EVIDENCE_RATE}, capped at\n * {@link POOL_QUESTION_MAX_DISCRIMINATORS}. Input is already VoI-sorted.\n */\nexport function selectQuestionDiscriminators(discriminators: ScoredDiscriminator[]): ScoredDiscriminator[] {\n return discriminators\n .filter((d) => d.voi >= POOL_QUESTION_MIN_VOI && d.evidenceRate >= POOL_QUESTION_MIN_EVIDENCE_RATE)\n .slice(0, POOL_QUESTION_MAX_DISCRIMINATORS);\n}\n\n/** Truncates a side label to the chip word budget. */\nfunction chipLabel(side: string): string {\n const words = side.trim().split(/\\s+/);\n return words.slice(0, MAX_LABEL_WORDS).join(\" \");\n}\n\n/**\n * Miner seeds are sometimes written from the intent owner's POV (\"Do I\n * prefer…\"). The question is asked TO the owner, so normalize to second\n * person. Conservative verb-pair map + bare pronoun/possessive swaps.\n */\nfunction toSecondPerson(seed: string): string {\n return seed\n .replace(/\\b(do|should|would|could|can|will) I\\b/gi, (_, verb: string) => `${verb.toLowerCase()} you`)\n .replace(/\\bam I\\b/gi, \"are you\")\n .replace(/\\bI\\b/g, \"you\")\n .replace(/\\bmy\\b/gi, \"your\")\n // Third-person seeds (\"Is the user primarily involved…\") — the question is\n // asked TO the owner, never ABOUT them.\n .replace(/\\b(is|was) the (user|owner|discoverer)\\b/gi, \"are you\")\n .replace(/\\bdoes the (user|owner|discoverer)\\b/gi, \"do you\")\n .replace(/\\bthe (user|owner|discoverer)'s\\b/gi, \"your\")\n .replace(/\\bthe (user|owner|discoverer)\\b/gi, \"you\");\n}\n\n/**\n * A good discriminator prompt names BOTH sides so the chips read as a real\n * choice. When the seed mentions fewer than two sides (e.g. \"Do you prefer\n * hands-on prototyping?\"), fall back to a deterministic two-sided template.\n */\nfunction mentionsSide(seed: string, side: string): boolean {\n const lowerSeed = seed.toLowerCase();\n return side\n .toLowerCase()\n .split(/[^a-z0-9-]+/)\n .filter((w) => w.length > 3)\n .some((w) => lowerSeed.includes(w));\n}\n\n/** Ensures the prompt reads as one second-person, two-sided question. */\nfunction toPrompt(questionSeed: string, sides: string[]): string {\n let p = toSecondPerson(questionSeed.trim().replace(/\\s+/g, \" \"));\n const sidesMentioned = sides.filter((s) => mentionsSide(p, s)).length;\n if (sidesMentioned < 2) {\n const last = sides[sides.length - 1];\n const head = sides.slice(0, -1).join(\", \");\n p = `Which matters more here: ${head} or ${last}`;\n }\n // Sentence-case the first character (template + normalization can lowercase it).\n p = p.charAt(0).toUpperCase() + p.slice(1);\n if (!/[?]$/.test(p)) p = p.replace(/[.!]+$/, \"\") + \"?\";\n return p.slice(0, 400);\n}\n\n/** Input for one question synthesis. */\nexport interface SynthesizePoolQuestionInput {\n /** The discriminator to ask about (already eligibility-filtered). */\n discriminator: QuestionPoolDiscriminator;\n /** Remaining ranked eligible discriminators (interview-mode chain stash). */\n alternates: QuestionPoolDiscriminator[];\n poolSize: number;\n /** ISO-8601 timestamp of the mining pass. */\n minedAt: string;\n /** Discovery run id, when known. */\n runId?: string;\n /**\n * Intent payload snippet — folded into the evidence chip so the question\n * self-identifies on any surface (\"based on 16 people matching ‘…’\").\n */\n intentText?: string;\n}\n\n/** Synthesized question: client payload + server-side snapshot. */\nexport interface SynthesizedPoolQuestion {\n payload: Question;\n pool: QuestionPoolSnapshot;\n}\n\n/**\n * Builds the pool_discovery question. Returns null when the pool is below\n * the k-anonymity floor or the discriminator shape is unusable (guards are\n * duplicated here so no caller can bypass them).\n */\nexport function synthesizePoolQuestion(input: SynthesizePoolQuestionInput): SynthesizedPoolQuestion | null {\n const { discriminator: d, poolSize } = input;\n if (poolSize < POOL_DISCRIMINATOR_MIN_POOL_SIZE) return null;\n if (d.sides.length < 2 || d.sides.length > 3) return null;\n\n // Evidence chip: aggregate count + the intent it belongs to, so the card is\n // self-identifying on every surface (QuestionSchema caps evidence at 160).\n const snippet = input.intentText?.trim().replace(/\\s+/g, \" \") ?? \"\";\n const evidence = snippet.length > 0\n ? `based on ${poolSize} people matching “${snippet.slice(0, 110)}${snippet.length > 110 ? \"…\" : \"\"}”`\n : `based on ${poolSize} people matching this intent`;\n\n const sideOptions: QuestionOption[] = d.sides.map((side) => ({\n label: chipLabel(side),\n description: `${d.sideCounts[side] ?? 0} of your ${poolSize} current matches lean this way`,\n }));\n const options: QuestionOption[] = [\n ...sideOptions,\n {\n label: BOTH_MATTER_LABEL,\n description: \"No preference — keep the current ranking\",\n },\n ];\n\n return {\n payload: {\n title: POOL_QUESTION_TITLE,\n prompt: toPrompt(d.questionSeed, d.sides),\n options,\n multiSelect: false,\n evidence,\n },\n pool: {\n poolSize,\n minedAt: input.minedAt,\n ...(input.runId ? { runId: input.runId } : {}),\n ...(snippet.length > 0 ? { intentText: snippet.slice(0, 160) } : {}),\n discriminator: d,\n alternates: input.alternates,\n },\n };\n}\n"]}
1
+ {"version":3,"file":"discriminator.question.js","sourceRoot":"/","sources":["opportunity/discriminator/discriminator.question.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Deterministic pool_discovery question synthesis (IND-418).\n *\n * A mined discriminator already carries everything a question needs: a label,\n * a question seed, 2–3 sides, and verified per-candidate assignments. This\n * module turns the top discriminator into a `Question` payload + server-side\n * pool snapshot with ZERO generation-time LLM calls — the phrasing was\n * produced (and evidence-verified) at mining time, so synthesis is pure,\n * auditable, and cheap to re-run for interview-mode chaining.\n */\nimport type { Question, QuestionOption, QuestionPoolDiscriminator, QuestionPoolSnapshot } from \"../../shared/schemas/question.schema.js\";\nimport { POOL_DISCRIMINATOR_MIN_POOL_SIZE, POOL_QUESTION_MAX_DISCRIMINATORS, POOL_QUESTION_MIN_EVIDENCE_RATE, POOL_QUESTION_MIN_VOI } from \"./discriminator.env.js\";\nimport type { ScoredDiscriminator } from \"./discriminator.types.js\";\n\n/** Fixed option appended to every pool question — the no-preference escape. */\nexport const BOTH_MATTER_LABEL = \"Both matter\";\n\n/** Max words in a chip-style option label (prototype voice: terse, glanceable). */\nconst MAX_LABEL_WORDS = 5;\n\n/** Question title (≤12 chars, per QuestionSchema). */\nconst POOL_QUESTION_TITLE = \"Matches\";\n\n/**\n * Converts a scored discriminator into the compact snapshot form stored on\n * the question row (verified assignments only; unknowns dropped).\n */\nexport function toQuestionDiscriminator(d: ScoredDiscriminator): QuestionPoolDiscriminator {\n const sideCounts: Record<string, number> = {};\n for (const side of d.sides) sideCounts[side] = 0;\n const assignments: Array<{ opportunityId: string; side: string }> = [];\n for (const a of d.assignments) {\n if (a.side === null || !a.verified) continue;\n if (!(a.side in sideCounts)) continue;\n sideCounts[a.side] += 1;\n assignments.push({ opportunityId: a.id, side: a.side });\n }\n return {\n label: d.label,\n questionSeed: d.questionSeed,\n sides: d.sides,\n sideCounts,\n voi: d.voi,\n evidenceRate: d.evidenceRate,\n assignments,\n };\n}\n\n/**\n * Filters a mining pass down to question-eligible discriminators:\n * VoI ≥ {@link POOL_QUESTION_MIN_VOI}, evidenceRate ≥\n * {@link POOL_QUESTION_MIN_EVIDENCE_RATE}, capped at\n * {@link POOL_QUESTION_MAX_DISCRIMINATORS}. Input is already VoI-sorted.\n */\nexport function selectQuestionDiscriminators(discriminators: ScoredDiscriminator[]): ScoredDiscriminator[] {\n return discriminators\n .filter((d) => d.voi >= POOL_QUESTION_MIN_VOI && d.evidenceRate >= POOL_QUESTION_MIN_EVIDENCE_RATE)\n .slice(0, POOL_QUESTION_MAX_DISCRIMINATORS);\n}\n\n/** Truncates a side label to the chip word budget. */\nfunction chipLabel(side: string): string {\n const words = side.trim().split(/\\s+/);\n return words.slice(0, MAX_LABEL_WORDS).join(\" \");\n}\n\n/**\n * Miner seeds are sometimes written from the intent owner's POV (\"Do I\n * prefer…\"). The question is asked TO the owner, so normalize to second\n * person. Conservative verb-pair map + bare pronoun/possessive swaps.\n */\nfunction toSecondPerson(seed: string): string {\n return seed\n .replace(/\\b(do|should|would|could|can|will) I\\b/gi, (_, verb: string) => `${verb.toLowerCase()} you`)\n .replace(/\\bam I\\b/gi, \"are you\")\n .replace(/\\bI\\b/g, \"you\")\n .replace(/\\bmy\\b/gi, \"your\")\n // Third-person seeds (\"Is the user primarily involved…\") — the question is\n // asked TO the owner, never ABOUT them.\n .replace(/\\b(is|was) (?:the|this) (user|owner|discoverer|client)\\b/gi, \"are you\")\n .replace(/\\bdoes (?:the|this) (user|owner|discoverer|client)\\b/gi, \"do you\")\n .replace(/\\b(?:the|this) (user|owner|discoverer|client)'s\\b/gi, \"your\")\n .replace(/\\b(?:the|this) (user|owner|discoverer|client)\\b/gi, \"you\");\n}\n\n/**\n * Catch-all: after normalization the prompt must be second-person. Any\n * residual third-person reference to the owner means an unanticipated seed\n * shape slipped through — the deterministic two-sided template (always\n * second-person) is the safe fallback.\n */\nfunction isStillThirdPerson(prompt: string): boolean {\n return /\\b(?:the|this|a) (?:user|owner|discoverer|client)\\b/i.test(prompt);\n}\n\n/**\n * A good discriminator prompt names BOTH sides so the chips read as a real\n * choice. When the seed mentions fewer than two sides (e.g. \"Do you prefer\n * hands-on prototyping?\"), fall back to a deterministic two-sided template.\n */\nfunction mentionsSide(seed: string, side: string): boolean {\n const lowerSeed = seed.toLowerCase();\n return side\n .toLowerCase()\n .split(/[^a-z0-9-]+/)\n .filter((w) => w.length > 3)\n .some((w) => lowerSeed.includes(w));\n}\n\n/** Ensures the prompt reads as one second-person, two-sided question. */\nfunction toPrompt(questionSeed: string, sides: string[]): string {\n let p = toSecondPerson(questionSeed.trim().replace(/\\s+/g, \" \"));\n const sidesMentioned = sides.filter((s) => mentionsSide(p, s)).length;\n if (sidesMentioned < 2 || isStillThirdPerson(p)) {\n const last = sides[sides.length - 1];\n const head = sides.slice(0, -1).join(\", \");\n p = `Which matters more here: ${head} or ${last}`;\n }\n // Sentence-case the first character (template + normalization can lowercase it).\n p = p.charAt(0).toUpperCase() + p.slice(1);\n if (!/[?]$/.test(p)) p = p.replace(/[.!]+$/, \"\") + \"?\";\n return p.slice(0, 400);\n}\n\n/** Input for one question synthesis. */\nexport interface SynthesizePoolQuestionInput {\n /** The discriminator to ask about (already eligibility-filtered). */\n discriminator: QuestionPoolDiscriminator;\n /** Remaining ranked eligible discriminators (interview-mode chain stash). */\n alternates: QuestionPoolDiscriminator[];\n poolSize: number;\n /** ISO-8601 timestamp of the mining pass. */\n minedAt: string;\n /** Discovery run id, when known. */\n runId?: string;\n /**\n * Intent payload snippet — folded into the evidence chip so the question\n * self-identifies on any surface (\"based on 16 people matching ‘…’\").\n */\n intentText?: string;\n}\n\n/** Synthesized question: client payload + server-side snapshot. */\nexport interface SynthesizedPoolQuestion {\n payload: Question;\n pool: QuestionPoolSnapshot;\n}\n\n/**\n * Builds the pool_discovery question. Returns null when the pool is below\n * the k-anonymity floor or the discriminator shape is unusable (guards are\n * duplicated here so no caller can bypass them).\n */\nexport function synthesizePoolQuestion(input: SynthesizePoolQuestionInput): SynthesizedPoolQuestion | null {\n const { discriminator: d, poolSize } = input;\n if (poolSize < POOL_DISCRIMINATOR_MIN_POOL_SIZE) return null;\n if (d.sides.length < 2 || d.sides.length > 3) return null;\n\n // Evidence chip: aggregate count + the intent it belongs to, so the card is\n // self-identifying on every surface (QuestionSchema caps evidence at 160).\n const snippet = input.intentText?.trim().replace(/\\s+/g, \" \") ?? \"\";\n const evidence = snippet.length > 0\n ? `based on ${poolSize} people matching “${snippet.slice(0, 110)}${snippet.length > 110 ? \"…\" : \"\"}”`\n : `based on ${poolSize} people matching this intent`;\n\n const sideOptions: QuestionOption[] = d.sides.map((side) => ({\n label: chipLabel(side),\n description: `${d.sideCounts[side] ?? 0} of your ${poolSize} current matches lean this way`,\n }));\n const options: QuestionOption[] = [\n ...sideOptions,\n {\n label: BOTH_MATTER_LABEL,\n description: \"No preference — keep the current ranking\",\n },\n ];\n\n return {\n payload: {\n title: POOL_QUESTION_TITLE,\n prompt: toPrompt(d.questionSeed, d.sides),\n options,\n multiSelect: false,\n evidence,\n },\n pool: {\n poolSize,\n minedAt: input.minedAt,\n ...(input.runId ? { runId: input.runId } : {}),\n ...(snippet.length > 0 ? { intentText: snippet.slice(0, 160) } : {}),\n discriminator: d,\n alternates: input.alternates,\n },\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"feed.graph.d.ts","sourceRoot":"/","sources":["opportunity/feed/feed.graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;AAC1G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4CAA4C,CAAC;AACnF,OAAO,EAAkB,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,KAAK,mBAAmB,EAAwB,MAAM,iBAAiB,CAAC;AAQtI,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAczE,8HAA8H;AAC9H,KAAK,WAAW,GAAG,iBAAiB,CAAC;AAErC,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,QAAQ,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IACnC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,IAAI,EAAE;QAAE,kBAAkB,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,kFAAkF;AAClF,eAAO,MAAM,qBAAqB,EAAE,iBAAiB,EAA0B,CAAC;AAgBhF,0HAA0H;AAC1H,eAAO,MAAM,wBAAwB,EAAE,iBAAiB,EAEhC,CAAC;AAczB;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAarF;AA4ED,qBAAa,gBAAgB;IACf,OAAO,CAAC,QAAQ;IAAe,OAAO,CAAC,KAAK;gBAApC,QAAQ,EAAE,WAAW,EAAU,KAAK,EAAE,gBAAgB;IAE1E,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0oBZ"}
1
+ {"version":3,"file":"feed.graph.d.ts","sourceRoot":"/","sources":["opportunity/feed/feed.graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;AAC1G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4CAA4C,CAAC;AACnF,OAAO,EAAkB,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,KAAK,mBAAmB,EAAwB,MAAM,iBAAiB,CAAC;AAQtI,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAgBzE,8HAA8H;AAC9H,KAAK,WAAW,GAAG,iBAAiB,CAAC;AAErC,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,QAAQ,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IACnC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,IAAI,EAAE;QAAE,kBAAkB,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,kFAAkF;AAClF,eAAO,MAAM,qBAAqB,EAAE,iBAAiB,EAA0B,CAAC;AAgBhF,0HAA0H;AAC1H,eAAO,MAAM,wBAAwB,EAAE,iBAAiB,EAEhC,CAAC;AAczB;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAarF;AAwFD,qBAAa,gBAAgB;IACf,OAAO,CAAC,QAAQ;IAAe,OAAO,CAAC,KAAK;gBAApC,QAAQ,EAAE,WAAW,EAAU,KAAK,EAAE,gBAAgB;IAE1E,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuqBZ"}
@@ -21,6 +21,8 @@ import { safeFallbackSummary } from '../opportunity.safe-presentation.js';
21
21
  import { protocolLogger } from '../../shared/observability/protocol.logger.js';
22
22
  import { timed } from '../../shared/observability/performance.js';
23
23
  import { requestContext } from "../../shared/observability/request-context.js";
24
+ import { adjustedConfidence, latestPoolDemotionDetail } from '../discriminator/discriminator.adjustments.js';
25
+ import { poolQuestionsRanking } from '../discriminator/discriminator.env.js';
24
26
  const logger = protocolLogger('HomeGraph');
25
27
  const checkCategorizerCacheLog = protocolLogger('HomeGraph:checkCategorizerCache');
26
28
  const cacheCategorizerResultsLog = protocolLogger('HomeGraph:cacheCategorizerResults');
@@ -95,7 +97,7 @@ const safeParseDate = (value) => {
95
97
  return 0;
96
98
  };
97
99
  /** Confidence score for sorting (interpretation.confidence or opportunity.confidence). */
98
- const getConfidence = (opp) => {
100
+ const getRawConfidence = (opp) => {
99
101
  const fromInterp = opp.interpretation?.confidence;
100
102
  if (typeof fromInterp === 'number' && !Number.isNaN(fromInterp))
101
103
  return fromInterp;
@@ -114,6 +116,18 @@ const getConfidence = (opp) => {
114
116
  }
115
117
  return 0;
116
118
  };
119
+ /**
120
+ * Sort confidence, optionally pool-adjusted (IND-419): when
121
+ * POOL_QUESTIONS_RANKING=on, answered discriminators multiply confidence by
122
+ * their stored factors (floor 0.3) so the user's answers re-rank the feed.
123
+ * Flag off → identical to raw confidence (adjustments are write-only).
124
+ */
125
+ const getConfidence = (opp) => {
126
+ const raw = getRawConfidence(opp);
127
+ if (poolQuestionsRanking() !== 'on')
128
+ return raw;
129
+ return adjustedConfidence(raw, opp.metadata);
130
+ };
117
131
  /** Unique non-introducer, non-viewer userIds for an opportunity (actors can repeat). */
118
132
  const getUniqueCounterpartUserIds = (opp, viewerId) => {
119
133
  const ids = new Set();
@@ -211,7 +225,20 @@ export class HomeGraphFactory {
211
225
  seenIds.add(id);
212
226
  return true;
213
227
  });
214
- return { opportunities: dedupedByCounterpart.slice(0, state.limit) };
228
+ // Preserve byte-identical newest-first behavior while the flag is
229
+ // off. When on, re-order the already-deduped lifecycle set by
230
+ // adjusted confidence so each client-side radar bucket reflects
231
+ // pool answers immediately.
232
+ if (poolQuestionsRanking() !== 'on') {
233
+ return { opportunities: dedupedByCounterpart.slice(0, state.limit) };
234
+ }
235
+ const adjustedOrder = [...dedupedByCounterpart].sort((a, b) => {
236
+ const confidenceDelta = getConfidence(b) - getConfidence(a);
237
+ if (confidenceDelta !== 0)
238
+ return confidenceDelta;
239
+ return safeParseDate(b.updatedAt) - safeParseDate(a.updatedAt);
240
+ });
241
+ return { opportunities: adjustedOrder.slice(0, state.limit) };
215
242
  }
216
243
  const sorted = [...visibleForFeed].sort((a, b) => {
217
244
  // Connections before connector-flow so dedup claims counterpart IDs
@@ -278,7 +305,15 @@ export class HomeGraphFactory {
278
305
  const originalIndex = opportunities.indexOf(cacheable[i]);
279
306
  // Stamp the live status: pre-status cache entries lack the field,
280
307
  // and the key already guarantees it matches the current status.
281
- cachedCards.set(cacheable[i].id, { ...cached, status: cacheable[i].status, _cardIndex: originalIndex });
308
+ const deprioritizedReason = poolQuestionsRanking() === 'on'
309
+ ? latestPoolDemotionDetail(cacheable[i].metadata)
310
+ : undefined;
311
+ cachedCards.set(cacheable[i].id, {
312
+ ...cached,
313
+ status: cacheable[i].status,
314
+ deprioritizedReason,
315
+ _cardIndex: originalIndex,
316
+ });
282
317
  }
283
318
  else {
284
319
  uncachedOpportunities.push(cacheable[i]);
@@ -342,7 +377,6 @@ export class HomeGraphFactory {
342
377
  const viewerActor = opportunity.actors.find((a) => a.userId === state.userId);
343
378
  const viewerRole = viewerActor?.role ?? 'party';
344
379
  const isIntroducer = viewerRole === 'introducer';
345
- const isPendingIntroducer = isIntroducer && opportunity.status === 'pending';
346
380
  const preferredActor = pickDisplayCounterpartActor(opportunity, state.userId)
347
381
  ?? opportunity.actors.find((a) => a.userId !== state.userId && a.role !== 'introducer');
348
382
  const actorWithProfile = opportunity.actors.find((a) => a.userId !== state.userId && a.role !== 'introducer' && !!userMap.get(a.userId));
@@ -537,8 +571,16 @@ export class HomeGraphFactory {
537
571
  const cachePresenterResultsNode = async (state) => {
538
572
  return timed("HomeGraph.cachePresenterResults", async () => {
539
573
  const { cards, cachedCards, userId, opportunities } = state;
574
+ const liveById = new Map(opportunities.map((opportunity) => [opportunity.id, opportunity]));
575
+ const cardsWithAdjustments = cards.map((card) => {
576
+ const opportunity = liveById.get(card.opportunityId);
577
+ const deprioritizedReason = poolQuestionsRanking() === 'on'
578
+ ? latestPoolDemotionDetail(opportunity?.metadata)
579
+ : undefined;
580
+ return { ...card, deprioritizedReason };
581
+ });
540
582
  // Only cache cards that weren't already from cache
541
- const newCards = cards.filter((card) => !cachedCards.has(card.opportunityId));
583
+ const newCards = cardsWithAdjustments.filter((card) => !cachedCards.has(card.opportunityId));
542
584
  const statusById = new Map(opportunities.map((opp) => [opp.id, opp.status]));
543
585
  try {
544
586
  await Promise.all(newCards.map((card) => {
@@ -561,9 +603,9 @@ export class HomeGraphFactory {
561
603
  cachePresenterResultsLog.warn('cache write failed, continuing', { error: e });
562
604
  }
563
605
  // Merge cached cards into full card list
564
- const allCards = [...cards];
606
+ const allCards = [...cardsWithAdjustments];
565
607
  for (const [oppId, cachedCard] of cachedCards) {
566
- if (!cards.some((c) => c.opportunityId === oppId)) {
608
+ if (!cardsWithAdjustments.some((card) => card.opportunityId === oppId)) {
567
609
  allCards.push(cachedCard);
568
610
  }
569
611
  }
@@ -585,12 +627,13 @@ export class HomeGraphFactory {
585
627
  return { categoryCacheHit: false };
586
628
  }
587
629
  // Skeleton runs never categorize (some cards have no text to categorize
588
- // and the response must stay LLM-free): emit flat sections and mark the
589
- // categorizer as "hit" so the generate node and the cache write are both
590
- // skipped. Chunked by MAX_ITEMS_PER_SECTION because normalizeAndSort
591
- // caps every section one giant section would silently drop cards that
592
- // the follow-up full request (multiple sections) does return.
593
- if (state.presentation === 'skeleton') {
630
+ // and the response must stay LLM-free). Ranking-enabled lifecycle views
631
+ // also stay flat: the intent Radar flattens sections and buckets by
632
+ // status, so dynamic categorization would erase the adjusted order on
633
+ // the full second-phase response. Flag off retains the legacy path.
634
+ // Chunk by MAX_ITEMS_PER_SECTION because normalizeAndSort caps sections.
635
+ const preserveAdjustedLifecycleOrder = (state.statuses?.length ?? 0) > 0 && poolQuestionsRanking() === 'on';
636
+ if (state.presentation === 'skeleton' || preserveAdjustedLifecycleOrder) {
594
637
  const sectionProposals = [];
595
638
  for (let start = 0; start < state.cards.length; start += MAX_ITEMS_PER_SECTION) {
596
639
  sectionProposals.push({
@@ -1 +1 @@
1
- {"version":3,"file":"feed.graph.js","sourceRoot":"/","sources":["opportunity/feed/feed.graph.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Home Graph: Build the opportunity home view with dynamic sections.\n *\n * Independent of ChatGraph. Flow:\n * loadOpportunities → checkPresenterCache → [generateCardText if misses] → cachePresenterResults\n * → checkCategorizerCache → [categorizeDynamically if miss] → cacheCategorizerResults → normalizeAndSort\n *\n * Uses OpportunityPresenter for card text and an LLM to categorize cards into dynamic sections\n * with titles and Lucide icon names. Caches presenter and categorizer results via OpportunityCache.\n */\n\nimport { createHash } from 'crypto';\n\nimport { StateGraph, START, END } from '@langchain/langgraph';\n\nimport type { HomeGraphDatabase, OpportunityStatus } from '../../shared/interfaces/database.interface.js';\nimport type { OpportunityCache } from '../../shared/interfaces/cache.interface.js';\nimport { HomeGraphState, type HomeCardItem, type HomeSection, type HomeSectionProposal, type HomeSectionItem } from './feed.state.js';\nimport { OpportunityPresenter, gatherPresenterContext, type PresenterDatabase } from '../opportunity.presenter.js';\nimport { loadNegotiationContext } from '../negotiation-context.loader.js';\nimport { HomeCategorizerAgent } from './feed.categorizer.js';\nimport { canUserSeeOpportunity, isActionableForViewer, selectByComposition } from '../opportunity.utils.js';\nimport { resolveHomeSectionIcon, DEFAULT_HOME_SECTION_ICON } from '../../shared/ui/lucide.icon-catalog.js';\nimport { getPrimaryActionLabel, SECONDARY_ACTION_LABEL } from '../opportunity.labels.js';\nimport { safeFallbackSummary } from '../opportunity.safe-presentation.js';\nimport type { DebugMetaAgent } from '../../chat/chat-streaming.types.js';\nimport { protocolLogger } from '../../shared/observability/protocol.logger.js';\nimport { timed } from '../../shared/observability/performance.js';\nimport { requestContext } from \"../../shared/observability/request-context.js\";\n\nconst logger = protocolLogger('HomeGraph');\nconst checkCategorizerCacheLog = protocolLogger('HomeGraph:checkCategorizerCache');\nconst cacheCategorizerResultsLog = protocolLogger('HomeGraph:cacheCategorizerResults');\nconst checkPresenterCacheLog = protocolLogger('HomeGraph:checkPresenterCache');\nconst cachePresenterResultsLog = protocolLogger('HomeGraph:cachePresenterResults');\nconst categorizeDynamicallyLog = protocolLogger('HomeGraph:categorizeDynamically');\nconst normalizeAndSortLog = protocolLogger('HomeGraph:normalizeAndSort');\nconst generateCardTextLog = protocolLogger('HomeGraph:generateCardText');\n\n/** Database must satisfy both HomeGraphDatabase and presenter context (getProfile, getActiveIntents, getNetwork, getUser). */\ntype HomeGraphDb = HomeGraphDatabase;\n\nexport type HomeGraphInvokeInput = {\n userId: string;\n networkId?: string;\n scopeType?: 'intent';\n scopeId?: string;\n limit?: number;\n noCache?: boolean;\n /**\n * 'skeleton' returns immediately without LLM work: cached cards complete,\n * uncached cards with identity fields only + `presentationPending: true`,\n * single flat section (no categorizer). Meant as the fast first phase of a\n * two-phase fetch — follow up with a full request to fill in the text.\n */\n presentation?: 'full' | 'skeleton';\n /**\n * When set, filter loaded opportunities to these lifecycle statuses. Defaults to `DEFAULT_HOME_STATUSES`.\n * Explicit statuses switch the graph to \"lifecycle view\" mode: terminal/internal\n * statuses pass through (only latent/pending stay gated by viewer actionability),\n * ordering is newest-first, and feed composition capping is skipped.\n */\n statuses?: OpportunityStatus[];\n};\n\nexport type HomeGraphInvokeResult = {\n sections: HomeSection[];\n meta: { totalOpportunities: number; totalSections: number };\n error?: string;\n};\n\n/** Default home-feed statuses: the lifecycle stages a viewer can act on today. */\nexport const DEFAULT_HOME_STATUSES: OpportunityStatus[] = ['latent', 'pending'];\n\n// Exhaustive registry — keys must cover every OpportunityStatus union member.\n// Adding a new status to OpportunityStatus without adding a key here is a TS error,\n// which is the whole point: prevents ALL_OPPORTUNITY_STATUSES from silently drifting.\nconst OPPORTUNITY_STATUS_REGISTRY: Record<OpportunityStatus, true> = {\n latent: true,\n draft: true,\n negotiating: true,\n pending: true,\n stalled: true,\n accepted: true,\n rejected: true,\n expired: true,\n};\n\n/** Full status enumeration. Pass this to `HomeGraphInvokeInput.statuses` to restore pre-Issue-3 (unfiltered) behavior. */\nexport const ALL_OPPORTUNITY_STATUSES: OpportunityStatus[] = Object.keys(\n OPPORTUNITY_STATUS_REGISTRY,\n) as OpportunityStatus[];\n\nconst MAX_ITEMS_PER_SECTION = 20;\nconst PRESENTATION_CONCURRENCY = 50;\nconst MAX_REASONING_SNIPPET_LENGTH = 240;\nconst HOME_CACHE_TTL = 24 * 60 * 60; // 24 hours in seconds\n\n/** Redis key for the categorizer cache, derived from the user and the ordered opportunity-id set. */\nfunction buildCategorizerCacheKey(userId: string, cards: HomeCardItem[]): string {\n const oppIds = cards.map((c) => c.opportunityId).join(',');\n const hash = createHash('sha256').update(oppIds).digest('hex').slice(0, 16);\n return `home:categories:${userId}:${hash}`;\n}\n\n/**\n * Strip leading narrator name from remark when the UI already prepends \"Name: \" to the chip.\n * Avoids duplication like \"Yankı Ekin Yüksel: Yankı Ekin Yüksel introduced you two...\"\n * Repeats until no leading name (handles \"Name: Name rest\").\n */\nexport function stripLeadingNarratorName(remark: string, narratorName: string): string {\n let t = remark.trim();\n if (!t || !narratorName.trim()) return remark;\n const name = narratorName.trim();\n const nameLower = name.toLowerCase();\n for (;;) {\n const lower = t.toLowerCase();\n if (!lower.startsWith(nameLower)) break;\n const rest = t.slice(name.length).replace(/^\\s*[:,\\-–—]\\s*/i, '').trim();\n if (rest.length === 0 || rest === t) break;\n t = rest;\n }\n return t;\n}\n\n/** Normalize timestamp for sorting; returns numeric ms or 0 for invalid/missing. */\nconst safeParseDate = (value: unknown): number => {\n if (value == null) return 0;\n if (value instanceof Date) {\n const t = value.getTime();\n return Number.isFinite(t) ? t : 0;\n }\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n if (typeof value === 'string') {\n const t = new Date(value).getTime();\n return Number.isFinite(t) ? t : 0;\n }\n return 0;\n};\n\n/** Confidence score for sorting (interpretation.confidence or opportunity.confidence). */\nconst getConfidence = (opp: typeof HomeGraphState.State['opportunities'][number]): number => {\n const fromInterp = opp.interpretation?.confidence;\n if (typeof fromInterp === 'number' && !Number.isNaN(fromInterp)) return fromInterp;\n if (typeof fromInterp === 'string') {\n const n = parseFloat(fromInterp);\n if (!Number.isNaN(n)) return n;\n }\n const fromRow = opp.confidence;\n if (typeof fromRow === 'number' && !Number.isNaN(fromRow)) return fromRow;\n if (typeof fromRow === 'string') {\n const n = parseFloat(fromRow);\n if (!Number.isNaN(n)) return n;\n }\n return 0;\n};\n\n/** Unique non-introducer, non-viewer userIds for an opportunity (actors can repeat). */\nconst getUniqueCounterpartUserIds = (\n opp: typeof HomeGraphState.State['opportunities'][number],\n viewerId: string\n): Set<string> => {\n const ids = new Set<string>();\n for (const a of opp.actors) {\n if (a.role !== 'introducer' && a.userId !== viewerId && a.userId) {\n ids.add(a.userId);\n }\n }\n return ids;\n};\n\nconst pickDisplayCounterpartActor = (\n opportunity: typeof HomeGraphState.State['opportunities'][number],\n viewerId: string\n): { userId: string; role: string } | null => {\n const candidates = opportunity.actors.filter(\n (actor) => actor.userId !== viewerId && actor.role !== 'introducer'\n );\n if (candidates.length === 0) {\n return null;\n }\n\n // Prefer direct counterpart roles when available, then stable sort by user id.\n const rolePriority = new Map<string, number>([\n ['patient', 0],\n ['party', 1],\n ['agent', 2],\n ['peer', 3],\n ]);\n\n const sorted = [...candidates].sort((a, b) => {\n const aPriority = rolePriority.get(a.role) ?? 99;\n const bPriority = rolePriority.get(b.role) ?? 99;\n if (aPriority !== bPriority) return aPriority - bPriority;\n return a.userId.localeCompare(b.userId);\n });\n return sorted[0] ?? null;\n};\n\nexport class HomeGraphFactory {\n constructor(private database: HomeGraphDb, private cache: OpportunityCache) {}\n\n createGraph() {\n const presenter = new OpportunityPresenter();\n const categorizer = new HomeCategorizerAgent();\n\n const loadOpportunitiesNode = async (state: typeof HomeGraphState.State) => {\n return timed(\"HomeGraph.loadOpportunities\", async () => {\n if (!state.userId) {\n return { error: 'userId is required' };\n }\n try {\n // Minimum of 50 ensures enough candidates across all feed categories\n // (connection, connector-flow, expired) for selectByComposition to fill\n // its soft targets, even after visibility filtering and dedup.\n const fetchLimit = Math.min(150, Math.max(50, state.limit * 3));\n const statuses = state.statuses ?? DEFAULT_HOME_STATUSES;\n const options: { limit?: number; networkId?: string; scopeType?: 'intent'; scopeId?: string; statuses?: OpportunityStatus[] } = {\n limit: fetchLimit,\n statuses,\n };\n if (state.networkId) options.networkId = state.networkId;\n if (state.scopeType === 'intent' && state.scopeId) {\n options.scopeType = 'intent';\n options.scopeId = state.scopeId;\n }\n // Do not pass conversationId: home view excludes draft opportunities (chat-only drafts).\n const raw = await this.database.getOpportunitiesForUser(state.userId, options);\n const visible = raw.filter((opp) =>\n canUserSeeOpportunity(opp.actors, opp.status, state.userId)\n );\n // Actionability only gates the live statuses a viewer could act on:\n // latent/pending cards the viewer cannot act on are noise, but\n // terminal/internal statuses (accepted, rejected, expired, negotiating,\n // stalled, draft) are deliberate history — when a caller explicitly\n // requests them via `statuses`, they must pass through (they are never\n // actionable by rule 5, so filtering them here would return nothing).\n // The requested-status membership check is defense-in-depth: rows\n // outside the requested set are dropped even if the adapter drifts.\n const requestedStatuses = new Set<OpportunityStatus>(statuses);\n const visibleForFeed = visible.filter((opp) => {\n if (!requestedStatuses.has(opp.status)) return false;\n if (opp.status === 'latent' || opp.status === 'pending') {\n return isActionableForViewer(opp.actors, opp.status, state.userId);\n }\n return true;\n });\n const explicitStatuses = (state.statuses?.length ?? 0) > 0;\n if (explicitStatuses) {\n // Lifecycle view (e.g. intent radar): newest-first so counterpart\n // dedup keeps each person's most recent state (an accepted\n // opportunity supersedes an older pending one), no composition\n // capping — the caller wants the full pipeline up to `limit`.\n const newestFirst = [...visibleForFeed].sort(\n (a, b) => safeParseDate(b.updatedAt) - safeParseDate(a.updatedAt)\n );\n const seenIds = new Set<string>();\n const dedupedByCounterpart = newestFirst.filter((opp) => {\n const counterpartIds = getUniqueCounterpartUserIds(opp, state.userId);\n const hasOverlap = [...counterpartIds].some((id) => seenIds.has(id));\n if (hasOverlap) return false;\n for (const id of counterpartIds) seenIds.add(id);\n return true;\n });\n return { opportunities: dedupedByCounterpart.slice(0, state.limit) };\n }\n const sorted = [...visibleForFeed].sort((a, b) => {\n // Connections before connector-flow so dedup claims counterpart IDs\n // for direct connections first — prevents introducer cards from\n // shadowing a user's own connection opportunities.\n const aIsIntroducer = a.actors.some((ac) => ac.userId === state.userId && ac.role === 'introducer');\n const bIsIntroducer = b.actors.some((ac) => ac.userId === state.userId && ac.role === 'introducer');\n if (aIsIntroducer !== bIsIntroducer) return aIsIntroducer ? 1 : -1;\n const confA = getConfidence(a);\n const confB = getConfidence(b);\n if (confB !== confA) return confB - confA;\n const aTime = safeParseDate(a.updatedAt);\n const bTime = safeParseDate(b.updatedAt);\n return bTime - aTime;\n });\n const seenUserIds = new Set<string>();\n const deduped = sorted.filter((opp) => {\n const counterpartIds = getUniqueCounterpartUserIds(opp, state.userId);\n const hasOverlap = [...counterpartIds].some((id) => seenUserIds.has(id));\n if (hasOverlap) return false;\n for (const id of counterpartIds) seenUserIds.add(id);\n return true;\n });\n const opportunities = selectByComposition(deduped, state.userId);\n return { opportunities };\n } catch (e) {\n logger.error('HomeGraph loadOpportunities failed', { error: e });\n return { error: 'Failed to load opportunities', opportunities: [] };\n }\n });\n };\n\n const checkPresenterCacheNode = async (state: typeof HomeGraphState.State) => {\n return timed(\"HomeGraph.checkPresenterCache\", async () => {\n const { opportunities, userId } = state;\n if (opportunities.length === 0) {\n return { cachedCards: new Map(), uncachedOpportunities: [] };\n }\n\n if (state.noCache) {\n checkPresenterCacheLog.verbose('noCache=true, skipping cache');\n return { cachedCards: new Map(), uncachedOpportunities: opportunities };\n }\n\n try {\n // Negotiating cards are templated (no LLM call) and their text\n // depends on the live turn count, which changes between requests\n // without changing the opportunity status. Skip cache entirely\n // for them so each render reflects the current turn.\n //\n // For all other statuses, include status in the key so status\n // transitions (e.g. negotiating → pending) don't serve stale cards.\n const cacheable = opportunities.filter((opp) => opp.status !== 'negotiating');\n const liveNegotiating = opportunities.filter((opp) => opp.status === 'negotiating');\n\n const keys = cacheable.map(\n (opp) => `home:card:${opp.id}:${opp.status}:${userId}`\n );\n const results = keys.length > 0 ? await this.cache.mget<HomeCardItem>(keys) : [];\n\n const cachedCards = new Map<string, HomeCardItem>();\n const uncachedOpportunities: typeof opportunities = [...liveNegotiating];\n\n for (let i = 0; i < cacheable.length; i++) {\n const cached = results[i];\n if (cached) {\n const originalIndex = opportunities.indexOf(cacheable[i]);\n // Stamp the live status: pre-status cache entries lack the field,\n // and the key already guarantees it matches the current status.\n cachedCards.set(cacheable[i].id, { ...cached, status: cacheable[i].status, _cardIndex: originalIndex });\n } else {\n uncachedOpportunities.push(cacheable[i]);\n }\n }\n\n checkPresenterCacheLog.verbose('', {\n total: opportunities.length,\n cacheHits: cachedCards.size,\n cacheMisses: uncachedOpportunities.length,\n });\n\n return { cachedCards, uncachedOpportunities };\n } catch (e) {\n checkPresenterCacheLog.warn('cache unavailable, skipping', { error: e });\n return { cachedCards: new Map(), uncachedOpportunities: opportunities };\n }\n });\n };\n\n const shouldGenerateCards = (state: typeof HomeGraphState.State): string => {\n if (state.uncachedOpportunities.length > 0) {\n return 'generate';\n }\n logger.verbose('All presenter results cached, skipping generation');\n return 'skip';\n };\n\n const generateCardTextNode = async (state: typeof HomeGraphState.State) => {\n return timed(\"HomeGraph.generateCardText\", async () => {\n const opportunities = state.uncachedOpportunities.length > 0\n ? state.uncachedOpportunities\n : state.opportunities;\n generateCardTextLog.verbose('entry', { opportunitiesLength: opportunities.length, userId: state.userId });\n if (opportunities.length === 0) {\n generateCardTextLog.verbose('exit', { totalOpportunities: 0, totalSections: 0 });\n return { cards: [], agentTimings: [], meta: { totalOpportunities: 0, totalSections: 0 } };\n }\n const db = this.database as PresenterDatabase & HomeGraphDb;\n const cards: HomeCardItem[] = [];\n const relevantActorIds = new Set<string>();\n for (const opp of opportunities) {\n for (const a of opp.actors) {\n if (a.userId) relevantActorIds.add(a.userId);\n }\n }\n\n const userEntries = await Promise.all(\n Array.from(relevantActorIds).map(async (userId) => {\n try {\n const user = await this.database.getUser(userId);\n return [userId, user ?? null] as const;\n } catch {\n return [userId, null] as const;\n }\n })\n );\n const userMap = new Map(userEntries);\n\n const oppIndexMap = new Map(\n state.opportunities.map((opp, idx) => [opp.id, idx])\n );\n\n const agentTimingsAccum: DebugMetaAgent[] = [];\n\n for (let i = 0; i < opportunities.length; i += PRESENTATION_CONCURRENCY) {\n const chunk = opportunities.slice(i, i + PRESENTATION_CONCURRENCY);\n const chunkCards = await Promise.all(\n chunk.map(async (opportunity, offset) => {\n const cardIndex = oppIndexMap.get(opportunity.id) ?? (i + offset);\n const viewerActor = opportunity.actors.find((a) => a.userId === state.userId);\n const viewerRole = viewerActor?.role ?? 'party';\n const isIntroducer = viewerRole === 'introducer';\n const isPendingIntroducer = isIntroducer && opportunity.status === 'pending';\n const preferredActor = pickDisplayCounterpartActor(opportunity, state.userId)\n ?? opportunity.actors.find((a) => a.userId !== state.userId && a.role !== 'introducer');\n const actorWithProfile = opportunity.actors.find(\n (a) => a.userId !== state.userId && a.role !== 'introducer' && !!userMap.get(a.userId)\n );\n const introducer = opportunity.actors.find((a) => a.role === 'introducer');\n let otherActor = (preferredActor && userMap.get(preferredActor.userId))\n ? preferredActor\n : (actorWithProfile ?? preferredActor);\n // When the only other participant is the introducer (no separate party), use introducer as display counterpart so the card shows a name instead of \"Unknown\"\n if (!otherActor && introducer && introducer.userId !== state.userId && introducer.userId) {\n otherActor = { userId: introducer.userId, role: introducer.role };\n }\n const otherUser = otherActor ? userMap.get(otherActor.userId) ?? null : null;\n const introducerCounterparts = opportunity.actors.filter(\n (a) => a.userId !== state.userId && a.role !== 'introducer'\n );\n // Deduplicate by userId — actors array can contain multiple rows per user\n // (e.g. from different intents), which would produce repeated names.\n const uniqueCounterpartIds = [...new Set(introducerCounterparts.map((a) => a.userId))];\n const participantNames = uniqueCounterpartIds\n .map((uid) => userMap.get(uid)?.name ?? 'Unknown')\n .sort();\n // When secondPartyData will be present (2+ counterparts), use single counterpart name\n // because the frontend arrow layout renders \"card.name → secondParty.name\".\n // Using the joined \"A ↔ B\" format here would produce redundant \"A ↔ B → B\".\n // Only use the joined format when there is a single counterpart (no arrow layout).\n const willHaveSecondParty = isIntroducer && uniqueCounterpartIds.length > 1;\n let userName = isIntroducer && participantNames.length > 0 && !willHaveSecondParty\n ? participantNames.join(' ↔ ')\n : (otherUser?.name ?? 'Unknown');\n // Fallback to profile identity name when users.name is missing (e.g. profile has display name, users row does not)\n if ((userName === 'Unknown' || !userName?.trim()) && otherActor?.userId && db.getProfile) {\n const profile = await db.getProfile(otherActor.userId).catch((err) => {\n logger.debug('getProfile fallback failed', { otherActorUserId: otherActor.userId, error: err });\n return null;\n });\n const profileName = profile?.identity?.name?.trim();\n if (profileName) userName = profileName;\n }\n // Unresolvable display counterpart (deleted user: no users row, no\n // profile fallback). Drop the card entirely instead of rendering an\n // \"Unknown\" placeholder: such cards are unusable, excluded from the\n // presenter cache (see cachePresenterResults), and would otherwise\n // trigger a fresh presenter LLM call on every request — a permanent\n // cache miss that keeps the whole feed slow (~9s per load).\n if (userName === 'Unknown' || !userName?.trim()) {\n logger.verbose('[HomeGraph:generateCardText] dropping card with unresolvable counterpart', {\n opportunityId: opportunity.id,\n otherActorUserId: otherActor?.userId,\n });\n return null;\n }\n const userAvatar = otherUser?.avatar ?? null;\n // Shared sanitization standard (UUID strip, viewer-centric rewrite,\n // boundary truncation) — raw reasoning must never render verbatim.\n const reasoningSnippet = safeFallbackSummary(\n typeof opportunity.interpretation?.reasoning === 'string'\n ? opportunity.interpretation.reasoning\n : '',\n {\n counterpartName: userName !== 'Unknown' ? userName : undefined,\n maxChars: MAX_REASONING_SNIPPET_LENGTH,\n emptyText: 'A promising connection.',\n },\n );\n\n // Build secondParty for introducer arrow layout (the party that isn't the display counterpart)\n let secondPartyData: { name: string; avatar?: string | null; userId?: string } | undefined;\n if (isIntroducer && introducerCounterparts.length > 1 && otherActor) {\n const secondActor = introducerCounterparts.find((a) => a.userId !== otherActor.userId);\n if (secondActor) {\n const secondUser = userMap.get(secondActor.userId) ?? null;\n secondPartyData = {\n name: secondUser?.name ?? 'Unknown',\n avatar: secondUser?.avatar ?? null,\n userId: secondActor.userId,\n };\n }\n }\n\n const isCounterpartGhost = otherUser?.isGhost ?? false;\n // Skeleton presentation: return an identity-only card without the\n // presenter LLM or negotiation-context load. Name resolution and\n // the unresolvable-counterpart drop above still apply, so the card\n // set matches what the follow-up full request will return.\n if (state.presentation === 'skeleton') {\n return {\n opportunityId: opportunity.id,\n status: opportunity.status,\n userId: otherActor?.userId ?? '',\n name: userName,\n avatar: userAvatar,\n mainText: '',\n cta: '',\n primaryActionLabel: getPrimaryActionLabel(viewerRole),\n secondaryActionLabel: SECONDARY_ACTION_LABEL,\n mutualIntentsLabel: isIntroducer ? 'Connector match' : 'Shared interests',\n viewerRole,\n isGhost: isCounterpartGhost,\n ...(secondPartyData ? { secondParty: secondPartyData } : {}),\n presentationPending: true,\n _cardIndex: cardIndex,\n } satisfies HomeCardItem;\n }\n const isPendingIntroducerFallback = isIntroducer && opportunity.status !== 'latent';\n const fallbackCard = (): HomeCardItem => ({\n opportunityId: opportunity.id,\n status: opportunity.status,\n userId: otherActor?.userId ?? '',\n name: userName,\n avatar: userAvatar,\n mainText: reasoningSnippet,\n cta: isIntroducer\n ? (isPendingIntroducerFallback ? 'Share this introduction to get things started.' : 'Take a look and decide if this is a good match.')\n : 'Take a look and decide whether to reach out.',\n primaryActionLabel: getPrimaryActionLabel(viewerRole),\n secondaryActionLabel: SECONDARY_ACTION_LABEL,\n mutualIntentsLabel: isIntroducer ? 'Connector match' : 'Shared interests',\n narratorChip: isIntroducer\n ? { name: 'You', text: 'Worth a look.', userId: state.userId }\n : { name: 'Index', text: 'Worth a look.' },\n viewerRole,\n isGhost: isCounterpartGhost,\n ...(secondPartyData ? { secondParty: secondPartyData } : {}),\n _cardIndex: cardIndex,\n });\n\n try {\n const [ctx, negotiationContext] = await Promise.all([\n gatherPresenterContext(\n db,\n opportunity,\n state.userId,\n otherActor?.userId,\n ),\n loadNegotiationContext(db, opportunity.id, opportunity.status),\n ]);\n const homeInput = {\n ...ctx,\n mutualIntentCount: undefined,\n opportunityStatus: opportunity.status,\n ...(negotiationContext ? { negotiationContext } : {}),\n };\n const _traceEmitterPresenter = requestContext.getStore()?.traceEmitter;\n const presenterStart = Date.now();\n _traceEmitterPresenter?.({ type: \"agent_start\", name: \"opportunity-presenter\" });\n const presentation = await presenter.presentHomeCard(homeInput);\n const _presenterDuration = Date.now() - presenterStart;\n agentTimingsAccum.push({ name: 'opportunity.presenter', durationMs: _presenterDuration });\n _traceEmitterPresenter?.({ type: \"agent_end\", name: \"opportunity-presenter\", durationMs: _presenterDuration, summary: `Presented: ${userName}` });\n let narratorChip: { name: string; text: string; avatar?: string | null; userId?: string } | undefined;\n // Only show a person as narrator when they are the introducer and not the display counterpart\n // (bad data can have same user as introducer and party, e.g. \"Amina introduced you to Amina\")\n const introducerIsCounterpart = introducer && otherActor && introducer.userId === otherActor.userId;\n if (introducer && introducer.userId !== state.userId && !introducerIsCounterpart) {\n const introUser = userMap.get(introducer.userId) ?? null;\n const narratorName = introUser?.name ?? 'Someone';\n narratorChip = {\n name: narratorName,\n text: stripLeadingNarratorName(presentation.narratorRemark, narratorName),\n avatar: introUser?.avatar ?? null,\n userId: introducer.userId,\n };\n } else if (introducer?.userId === state.userId) {\n narratorChip = { name: 'You', text: presentation.narratorRemark, userId: state.userId };\n } else {\n narratorChip = { name: 'Index', text: presentation.narratorRemark };\n }\n return {\n opportunityId: opportunity.id,\n status: opportunity.status,\n userId: otherActor?.userId ?? '',\n name: userName,\n avatar: userAvatar,\n mainText: presentation.personalizedSummary,\n cta: presentation.suggestedAction,\n headline: presentation.headline,\n primaryActionLabel: getPrimaryActionLabel(viewerRole),\n secondaryActionLabel: SECONDARY_ACTION_LABEL,\n mutualIntentsLabel: presentation.mutualIntentsLabel,\n narratorChip,\n viewerRole,\n isGhost: isCounterpartGhost,\n ...(secondPartyData ? { secondParty: secondPartyData } : {}),\n _cardIndex: cardIndex,\n } satisfies HomeCardItem;\n } catch (e) {\n logger.warn('HomeGraph presenter failed for opportunity', { opportunityId: opportunity.id, error: e });\n return fallbackCard();\n }\n })\n );\n cards.push(...chunkCards.filter((c): c is HomeCardItem => c !== null));\n }\n generateCardTextLog.verbose('exit', { totalOpportunities: state.opportunities.length, totalSections: 0 });\n return {\n cards,\n agentTimings: agentTimingsAccum,\n meta: { totalOpportunities: state.opportunities.length, totalSections: 0 },\n };\n });\n };\n\n const cachePresenterResultsNode = async (state: typeof HomeGraphState.State) => {\n return timed(\"HomeGraph.cachePresenterResults\", async () => {\n const { cards, cachedCards, userId, opportunities } = state;\n\n // Only cache cards that weren't already from cache\n const newCards = cards.filter((card) => !cachedCards.has(card.opportunityId));\n const statusById = new Map(opportunities.map((opp) => [opp.id, opp.status]));\n\n try {\n await Promise.all(\n newCards.map((card) => {\n const status = statusById.get(card.opportunityId);\n // Skip persisting negotiating cards — see read-side note.\n if (!status || status === 'negotiating') return Promise.resolve();\n // Never cache skeleton cards — they carry no presenter text and\n // would otherwise be served as \"complete\" for the full TTL.\n if (card.presentationPending) return Promise.resolve();\n // Skip caching cards with unresolved names — transient DB failures\n // would persist \"Unknown\" placeholders for the full TTL.\n if (!card.name || card.name === 'Unknown') return Promise.resolve();\n return this.cache.set(\n `home:card:${card.opportunityId}:${status}:${userId}`,\n card,\n { ttl: HOME_CACHE_TTL }\n );\n })\n );\n } catch (e) {\n cachePresenterResultsLog.warn('cache write failed, continuing', { error: e });\n }\n\n // Merge cached cards into full card list\n const allCards: HomeCardItem[] = [...cards];\n for (const [oppId, cachedCard] of cachedCards) {\n if (!cards.some((c) => c.opportunityId === oppId)) {\n allCards.push(cachedCard);\n }\n }\n\n // Re-sort by _cardIndex to maintain original ordering\n allCards.sort((a, b) => a._cardIndex - b._cardIndex);\n\n cachePresenterResultsLog.verbose('', {\n newlyCached: newCards.length,\n totalCards: allCards.length,\n });\n\n return {\n cards: allCards,\n meta: { totalOpportunities: state.opportunities.length, totalSections: 0 },\n };\n });\n };\n\n const checkCategorizerCacheNode = async (state: typeof HomeGraphState.State) => {\n return timed(\"HomeGraph.checkCategorizerCache\", async () => {\n if (state.cards.length === 0) {\n return { categoryCacheHit: false };\n }\n\n // Skeleton runs never categorize (some cards have no text to categorize\n // and the response must stay LLM-free): emit flat sections and mark the\n // categorizer as \"hit\" so the generate node and the cache write are both\n // skipped. Chunked by MAX_ITEMS_PER_SECTION because normalizeAndSort\n // caps every section — one giant section would silently drop cards that\n // the follow-up full request (multiple sections) does return.\n if (state.presentation === 'skeleton') {\n const sectionProposals: HomeSectionProposal[] = [];\n for (let start = 0; start < state.cards.length; start += MAX_ITEMS_PER_SECTION) {\n sectionProposals.push({\n id: `all-${sectionProposals.length + 1}`,\n title: 'All matches',\n iconName: DEFAULT_HOME_SECTION_ICON,\n itemIndices: state.cards.slice(start, start + MAX_ITEMS_PER_SECTION).map((_, i) => start + i),\n });\n }\n return { sectionProposals, categoryCacheHit: true };\n }\n\n if (state.noCache) {\n checkCategorizerCacheLog.verbose('noCache=true, skipping cache');\n return { categoryCacheHit: false };\n }\n\n try {\n const key = buildCategorizerCacheKey(state.userId, state.cards);\n\n const cached = await this.cache.get<HomeSectionProposal[]>(key);\n if (cached) {\n checkCategorizerCacheLog.verbose('cache hit');\n return { sectionProposals: cached, categoryCacheHit: true };\n }\n\n checkCategorizerCacheLog.verbose('cache miss');\n } catch (e) {\n checkCategorizerCacheLog.warn('cache unavailable, skipping', { error: e });\n }\n return { categoryCacheHit: false };\n });\n };\n\n const shouldCategorize = (state: typeof HomeGraphState.State): string => {\n if (state.categoryCacheHit) {\n logger.verbose('Categorizer results cached, skipping');\n return 'skip';\n }\n return 'categorize';\n };\n\n const categorizeDynamicallyNode = async (state: typeof HomeGraphState.State) => {\n return timed(\"HomeGraph.categorizeDynamically\", async () => {\n categorizeDynamicallyLog.verbose('entry', { cardsLength: state.cards.length });\n if (state.cards.length === 0) {\n categorizeDynamicallyLog.verbose('exit', { sectionProposalsCount: 0 });\n return { sectionProposals: [], agentTimings: [] };\n }\n const agentTimingsAccum: DebugMetaAgent[] = [];\n const categorizerInput = state.cards.map((c) => ({\n index: c._cardIndex,\n headline: c.headline,\n mainText: c.mainText,\n name: c.name,\n viewerRole: c.viewerRole === 'introducer' ? 'introducer' : undefined,\n opportunityStatus: c.viewerRole === 'introducer' ? 'pending' : undefined,\n }));\n const _traceEmitterCategorizer = requestContext.getStore()?.traceEmitter;\n const categorizerStart = Date.now();\n _traceEmitterCategorizer?.({ type: \"agent_start\", name: \"home-categorizer\" });\n const { sections } = await categorizer.categorize(categorizerInput);\n const _categorizerDuration = Date.now() - categorizerStart;\n agentTimingsAccum.push({ name: 'home.categorizer', durationMs: _categorizerDuration });\n _traceEmitterCategorizer?.({ type: \"agent_end\", name: \"home-categorizer\", durationMs: _categorizerDuration, summary: `Categorized into ${sections.length} section(s)` });\n const proposals: HomeSectionProposal[] = sections.map((s) => ({\n ...s,\n itemIndices: s.itemIndices.filter((i) => i >= 0 && i < state.cards.length),\n }));\n categorizeDynamicallyLog.verbose('exit', { sectionProposalsCount: proposals.length });\n return { sectionProposals: proposals, agentTimings: agentTimingsAccum };\n });\n };\n\n const cacheCategorizerResultsNode = async (state: typeof HomeGraphState.State) => {\n return timed(\"HomeGraph.cacheCategorizerResults\", async () => {\n if (state.categoryCacheHit || state.sectionProposals.length === 0) {\n return {};\n }\n\n try {\n const key = buildCategorizerCacheKey(state.userId, state.cards);\n\n await this.cache.set(key, state.sectionProposals, { ttl: HOME_CACHE_TTL });\n\n cacheCategorizerResultsLog.verbose('cached', {\n sectionCount: state.sectionProposals.length,\n });\n } catch (e) {\n cacheCategorizerResultsLog.warn('cache write failed, continuing', { error: e });\n }\n\n return {};\n });\n };\n\n const normalizeAndSortNode = async (state: typeof HomeGraphState.State) => {\n return timed(\"HomeGraph.normalizeAndSort\", async () => {\n const cards = state.cards;\n const proposals = state.sectionProposals;\n normalizeAndSortLog.verbose('entry', { cardsLength: cards.length, proposalsLength: proposals.length });\n if (cards.length === 0) {\n normalizeAndSortLog.verbose('exit', { totalOpportunities: 0, totalSections: 0 });\n return { sections: [], meta: { totalOpportunities: 0, totalSections: 0 } };\n }\n const usedIndices = new Set<number>();\n const sections: HomeSection[] = proposals.map((p) => {\n const iconName = resolveHomeSectionIcon(p.iconName);\n const items: HomeSectionItem[] = p.itemIndices\n .filter((i) => i >= 0 && i < cards.length && !usedIndices.has(i))\n .slice(0, MAX_ITEMS_PER_SECTION)\n .map((i) => {\n usedIndices.add(i);\n const card = cards[i];\n const { _cardIndex, ...rest } = card;\n return rest;\n });\n return {\n id: p.id,\n title: p.title,\n subtitle: p.subtitle,\n iconName,\n items,\n };\n });\n\n // Enforce category ordering: sections with connections first, then\n // connector-flow only, then expired only. This prevents the LLM\n // categorizer from placing introducer sections before connection sections.\n const sectionCategoryPriority = (section: HomeSection): number => {\n const hasConnection = section.items.some((item) => item.viewerRole !== 'introducer');\n if (hasConnection) return 0; // mixed or connection-only sections first\n const hasConnectorFlow = section.items.some((item) => item.viewerRole === 'introducer');\n if (hasConnectorFlow) return 1; // connector-flow only sections next\n return 2; // empty or expired sections last\n };\n sections.sort((a, b) => sectionCategoryPriority(a) - sectionCategoryPriority(b));\n const meta = {\n totalOpportunities: state.opportunities.length,\n totalSections: sections.length,\n };\n normalizeAndSortLog.verbose('exit', { totalOpportunities: meta.totalOpportunities, totalSections: meta.totalSections });\n return { sections, meta };\n });\n };\n\n const graph = new StateGraph(HomeGraphState)\n .addNode('loadOpportunities', loadOpportunitiesNode)\n .addNode('checkPresenterCache', checkPresenterCacheNode)\n .addNode('generateCardText', generateCardTextNode)\n .addNode('cachePresenterResults', cachePresenterResultsNode)\n .addNode('checkCategorizerCache', checkCategorizerCacheNode)\n .addNode('categorizeDynamically', categorizeDynamicallyNode)\n .addNode('cacheCategorizerResults', cacheCategorizerResultsNode)\n .addNode('normalizeAndSort', normalizeAndSortNode)\n .addEdge(START, 'loadOpportunities')\n .addEdge('loadOpportunities', 'checkPresenterCache')\n .addConditionalEdges('checkPresenterCache', shouldGenerateCards, {\n generate: 'generateCardText',\n skip: 'cachePresenterResults',\n })\n .addEdge('generateCardText', 'cachePresenterResults')\n .addEdge('cachePresenterResults', 'checkCategorizerCache')\n .addConditionalEdges('checkCategorizerCache', shouldCategorize, {\n categorize: 'categorizeDynamically',\n skip: 'normalizeAndSort',\n })\n .addEdge('categorizeDynamically', 'cacheCategorizerResults')\n .addEdge('cacheCategorizerResults', 'normalizeAndSort')\n .addEdge('normalizeAndSort', END);\n\n return graph.compile();\n }\n}\n"]}
1
+ {"version":3,"file":"feed.graph.js","sourceRoot":"/","sources":["opportunity/feed/feed.graph.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Home Graph: Build the opportunity home view with dynamic sections.\n *\n * Independent of ChatGraph. Flow:\n * loadOpportunities → checkPresenterCache → [generateCardText if misses] → cachePresenterResults\n * → checkCategorizerCache → [categorizeDynamically if miss] → cacheCategorizerResults → normalizeAndSort\n *\n * Uses OpportunityPresenter for card text and an LLM to categorize cards into dynamic sections\n * with titles and Lucide icon names. Caches presenter and categorizer results via OpportunityCache.\n */\n\nimport { createHash } from 'crypto';\n\nimport { StateGraph, START, END } from '@langchain/langgraph';\n\nimport type { HomeGraphDatabase, OpportunityStatus } from '../../shared/interfaces/database.interface.js';\nimport type { OpportunityCache } from '../../shared/interfaces/cache.interface.js';\nimport { HomeGraphState, type HomeCardItem, type HomeSection, type HomeSectionProposal, type HomeSectionItem } from './feed.state.js';\nimport { OpportunityPresenter, gatherPresenterContext, type PresenterDatabase } from '../opportunity.presenter.js';\nimport { loadNegotiationContext } from '../negotiation-context.loader.js';\nimport { HomeCategorizerAgent } from './feed.categorizer.js';\nimport { canUserSeeOpportunity, isActionableForViewer, selectByComposition } from '../opportunity.utils.js';\nimport { resolveHomeSectionIcon, DEFAULT_HOME_SECTION_ICON } from '../../shared/ui/lucide.icon-catalog.js';\nimport { getPrimaryActionLabel, SECONDARY_ACTION_LABEL } from '../opportunity.labels.js';\nimport { safeFallbackSummary } from '../opportunity.safe-presentation.js';\nimport type { DebugMetaAgent } from '../../chat/chat-streaming.types.js';\nimport { protocolLogger } from '../../shared/observability/protocol.logger.js';\nimport { timed } from '../../shared/observability/performance.js';\nimport { requestContext } from \"../../shared/observability/request-context.js\";\nimport { adjustedConfidence, latestPoolDemotionDetail } from '../discriminator/discriminator.adjustments.js';\nimport { poolQuestionsRanking } from '../discriminator/discriminator.env.js';\n\nconst logger = protocolLogger('HomeGraph');\nconst checkCategorizerCacheLog = protocolLogger('HomeGraph:checkCategorizerCache');\nconst cacheCategorizerResultsLog = protocolLogger('HomeGraph:cacheCategorizerResults');\nconst checkPresenterCacheLog = protocolLogger('HomeGraph:checkPresenterCache');\nconst cachePresenterResultsLog = protocolLogger('HomeGraph:cachePresenterResults');\nconst categorizeDynamicallyLog = protocolLogger('HomeGraph:categorizeDynamically');\nconst normalizeAndSortLog = protocolLogger('HomeGraph:normalizeAndSort');\nconst generateCardTextLog = protocolLogger('HomeGraph:generateCardText');\n\n/** Database must satisfy both HomeGraphDatabase and presenter context (getProfile, getActiveIntents, getNetwork, getUser). */\ntype HomeGraphDb = HomeGraphDatabase;\n\nexport type HomeGraphInvokeInput = {\n userId: string;\n networkId?: string;\n scopeType?: 'intent';\n scopeId?: string;\n limit?: number;\n noCache?: boolean;\n /**\n * 'skeleton' returns immediately without LLM work: cached cards complete,\n * uncached cards with identity fields only + `presentationPending: true`,\n * single flat section (no categorizer). Meant as the fast first phase of a\n * two-phase fetch — follow up with a full request to fill in the text.\n */\n presentation?: 'full' | 'skeleton';\n /**\n * When set, filter loaded opportunities to these lifecycle statuses. Defaults to `DEFAULT_HOME_STATUSES`.\n * Explicit statuses switch the graph to \"lifecycle view\" mode: terminal/internal\n * statuses pass through (only latent/pending stay gated by viewer actionability),\n * ordering is newest-first, and feed composition capping is skipped.\n */\n statuses?: OpportunityStatus[];\n};\n\nexport type HomeGraphInvokeResult = {\n sections: HomeSection[];\n meta: { totalOpportunities: number; totalSections: number };\n error?: string;\n};\n\n/** Default home-feed statuses: the lifecycle stages a viewer can act on today. */\nexport const DEFAULT_HOME_STATUSES: OpportunityStatus[] = ['latent', 'pending'];\n\n// Exhaustive registry — keys must cover every OpportunityStatus union member.\n// Adding a new status to OpportunityStatus without adding a key here is a TS error,\n// which is the whole point: prevents ALL_OPPORTUNITY_STATUSES from silently drifting.\nconst OPPORTUNITY_STATUS_REGISTRY: Record<OpportunityStatus, true> = {\n latent: true,\n draft: true,\n negotiating: true,\n pending: true,\n stalled: true,\n accepted: true,\n rejected: true,\n expired: true,\n};\n\n/** Full status enumeration. Pass this to `HomeGraphInvokeInput.statuses` to restore pre-Issue-3 (unfiltered) behavior. */\nexport const ALL_OPPORTUNITY_STATUSES: OpportunityStatus[] = Object.keys(\n OPPORTUNITY_STATUS_REGISTRY,\n) as OpportunityStatus[];\n\nconst MAX_ITEMS_PER_SECTION = 20;\nconst PRESENTATION_CONCURRENCY = 50;\nconst MAX_REASONING_SNIPPET_LENGTH = 240;\nconst HOME_CACHE_TTL = 24 * 60 * 60; // 24 hours in seconds\n\n/** Redis key for the categorizer cache, derived from the user and the ordered opportunity-id set. */\nfunction buildCategorizerCacheKey(userId: string, cards: HomeCardItem[]): string {\n const oppIds = cards.map((c) => c.opportunityId).join(',');\n const hash = createHash('sha256').update(oppIds).digest('hex').slice(0, 16);\n return `home:categories:${userId}:${hash}`;\n}\n\n/**\n * Strip leading narrator name from remark when the UI already prepends \"Name: \" to the chip.\n * Avoids duplication like \"Yankı Ekin Yüksel: Yankı Ekin Yüksel introduced you two...\"\n * Repeats until no leading name (handles \"Name: Name rest\").\n */\nexport function stripLeadingNarratorName(remark: string, narratorName: string): string {\n let t = remark.trim();\n if (!t || !narratorName.trim()) return remark;\n const name = narratorName.trim();\n const nameLower = name.toLowerCase();\n for (;;) {\n const lower = t.toLowerCase();\n if (!lower.startsWith(nameLower)) break;\n const rest = t.slice(name.length).replace(/^\\s*[:,\\-–—]\\s*/i, '').trim();\n if (rest.length === 0 || rest === t) break;\n t = rest;\n }\n return t;\n}\n\n/** Normalize timestamp for sorting; returns numeric ms or 0 for invalid/missing. */\nconst safeParseDate = (value: unknown): number => {\n if (value == null) return 0;\n if (value instanceof Date) {\n const t = value.getTime();\n return Number.isFinite(t) ? t : 0;\n }\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n if (typeof value === 'string') {\n const t = new Date(value).getTime();\n return Number.isFinite(t) ? t : 0;\n }\n return 0;\n};\n\n/** Confidence score for sorting (interpretation.confidence or opportunity.confidence). */\nconst getRawConfidence = (opp: typeof HomeGraphState.State['opportunities'][number]): number => {\n const fromInterp = opp.interpretation?.confidence;\n if (typeof fromInterp === 'number' && !Number.isNaN(fromInterp)) return fromInterp;\n if (typeof fromInterp === 'string') {\n const n = parseFloat(fromInterp);\n if (!Number.isNaN(n)) return n;\n }\n const fromRow = opp.confidence;\n if (typeof fromRow === 'number' && !Number.isNaN(fromRow)) return fromRow;\n if (typeof fromRow === 'string') {\n const n = parseFloat(fromRow);\n if (!Number.isNaN(n)) return n;\n }\n return 0;\n};\n\n/**\n * Sort confidence, optionally pool-adjusted (IND-419): when\n * POOL_QUESTIONS_RANKING=on, answered discriminators multiply confidence by\n * their stored factors (floor 0.3) so the user's answers re-rank the feed.\n * Flag off → identical to raw confidence (adjustments are write-only).\n */\nconst getConfidence = (opp: typeof HomeGraphState.State['opportunities'][number]): number => {\n const raw = getRawConfidence(opp);\n if (poolQuestionsRanking() !== 'on') return raw;\n return adjustedConfidence(raw, (opp as { metadata?: Record<string, unknown> | null }).metadata);\n};\n\n/** Unique non-introducer, non-viewer userIds for an opportunity (actors can repeat). */\nconst getUniqueCounterpartUserIds = (\n opp: typeof HomeGraphState.State['opportunities'][number],\n viewerId: string\n): Set<string> => {\n const ids = new Set<string>();\n for (const a of opp.actors) {\n if (a.role !== 'introducer' && a.userId !== viewerId && a.userId) {\n ids.add(a.userId);\n }\n }\n return ids;\n};\n\nconst pickDisplayCounterpartActor = (\n opportunity: typeof HomeGraphState.State['opportunities'][number],\n viewerId: string\n): { userId: string; role: string } | null => {\n const candidates = opportunity.actors.filter(\n (actor) => actor.userId !== viewerId && actor.role !== 'introducer'\n );\n if (candidates.length === 0) {\n return null;\n }\n\n // Prefer direct counterpart roles when available, then stable sort by user id.\n const rolePriority = new Map<string, number>([\n ['patient', 0],\n ['party', 1],\n ['agent', 2],\n ['peer', 3],\n ]);\n\n const sorted = [...candidates].sort((a, b) => {\n const aPriority = rolePriority.get(a.role) ?? 99;\n const bPriority = rolePriority.get(b.role) ?? 99;\n if (aPriority !== bPriority) return aPriority - bPriority;\n return a.userId.localeCompare(b.userId);\n });\n return sorted[0] ?? null;\n};\n\nexport class HomeGraphFactory {\n constructor(private database: HomeGraphDb, private cache: OpportunityCache) {}\n\n createGraph() {\n const presenter = new OpportunityPresenter();\n const categorizer = new HomeCategorizerAgent();\n\n const loadOpportunitiesNode = async (state: typeof HomeGraphState.State) => {\n return timed(\"HomeGraph.loadOpportunities\", async () => {\n if (!state.userId) {\n return { error: 'userId is required' };\n }\n try {\n // Minimum of 50 ensures enough candidates across all feed categories\n // (connection, connector-flow, expired) for selectByComposition to fill\n // its soft targets, even after visibility filtering and dedup.\n const fetchLimit = Math.min(150, Math.max(50, state.limit * 3));\n const statuses = state.statuses ?? DEFAULT_HOME_STATUSES;\n const options: { limit?: number; networkId?: string; scopeType?: 'intent'; scopeId?: string; statuses?: OpportunityStatus[] } = {\n limit: fetchLimit,\n statuses,\n };\n if (state.networkId) options.networkId = state.networkId;\n if (state.scopeType === 'intent' && state.scopeId) {\n options.scopeType = 'intent';\n options.scopeId = state.scopeId;\n }\n // Do not pass conversationId: home view excludes draft opportunities (chat-only drafts).\n const raw = await this.database.getOpportunitiesForUser(state.userId, options);\n const visible = raw.filter((opp) =>\n canUserSeeOpportunity(opp.actors, opp.status, state.userId)\n );\n // Actionability only gates the live statuses a viewer could act on:\n // latent/pending cards the viewer cannot act on are noise, but\n // terminal/internal statuses (accepted, rejected, expired, negotiating,\n // stalled, draft) are deliberate history — when a caller explicitly\n // requests them via `statuses`, they must pass through (they are never\n // actionable by rule 5, so filtering them here would return nothing).\n // The requested-status membership check is defense-in-depth: rows\n // outside the requested set are dropped even if the adapter drifts.\n const requestedStatuses = new Set<OpportunityStatus>(statuses);\n const visibleForFeed = visible.filter((opp) => {\n if (!requestedStatuses.has(opp.status)) return false;\n if (opp.status === 'latent' || opp.status === 'pending') {\n return isActionableForViewer(opp.actors, opp.status, state.userId);\n }\n return true;\n });\n const explicitStatuses = (state.statuses?.length ?? 0) > 0;\n if (explicitStatuses) {\n // Lifecycle view (e.g. intent radar): newest-first so counterpart\n // dedup keeps each person's most recent state (an accepted\n // opportunity supersedes an older pending one), no composition\n // capping — the caller wants the full pipeline up to `limit`.\n const newestFirst = [...visibleForFeed].sort(\n (a, b) => safeParseDate(b.updatedAt) - safeParseDate(a.updatedAt)\n );\n const seenIds = new Set<string>();\n const dedupedByCounterpart = newestFirst.filter((opp) => {\n const counterpartIds = getUniqueCounterpartUserIds(opp, state.userId);\n const hasOverlap = [...counterpartIds].some((id) => seenIds.has(id));\n if (hasOverlap) return false;\n for (const id of counterpartIds) seenIds.add(id);\n return true;\n });\n // Preserve byte-identical newest-first behavior while the flag is\n // off. When on, re-order the already-deduped lifecycle set by\n // adjusted confidence so each client-side radar bucket reflects\n // pool answers immediately.\n if (poolQuestionsRanking() !== 'on') {\n return { opportunities: dedupedByCounterpart.slice(0, state.limit) };\n }\n const adjustedOrder = [...dedupedByCounterpart].sort((a, b) => {\n const confidenceDelta = getConfidence(b) - getConfidence(a);\n if (confidenceDelta !== 0) return confidenceDelta;\n return safeParseDate(b.updatedAt) - safeParseDate(a.updatedAt);\n });\n return { opportunities: adjustedOrder.slice(0, state.limit) };\n }\n const sorted = [...visibleForFeed].sort((a, b) => {\n // Connections before connector-flow so dedup claims counterpart IDs\n // for direct connections first — prevents introducer cards from\n // shadowing a user's own connection opportunities.\n const aIsIntroducer = a.actors.some((ac) => ac.userId === state.userId && ac.role === 'introducer');\n const bIsIntroducer = b.actors.some((ac) => ac.userId === state.userId && ac.role === 'introducer');\n if (aIsIntroducer !== bIsIntroducer) return aIsIntroducer ? 1 : -1;\n const confA = getConfidence(a);\n const confB = getConfidence(b);\n if (confB !== confA) return confB - confA;\n const aTime = safeParseDate(a.updatedAt);\n const bTime = safeParseDate(b.updatedAt);\n return bTime - aTime;\n });\n const seenUserIds = new Set<string>();\n const deduped = sorted.filter((opp) => {\n const counterpartIds = getUniqueCounterpartUserIds(opp, state.userId);\n const hasOverlap = [...counterpartIds].some((id) => seenUserIds.has(id));\n if (hasOverlap) return false;\n for (const id of counterpartIds) seenUserIds.add(id);\n return true;\n });\n const opportunities = selectByComposition(deduped, state.userId);\n return { opportunities };\n } catch (e) {\n logger.error('HomeGraph loadOpportunities failed', { error: e });\n return { error: 'Failed to load opportunities', opportunities: [] };\n }\n });\n };\n\n const checkPresenterCacheNode = async (state: typeof HomeGraphState.State) => {\n return timed(\"HomeGraph.checkPresenterCache\", async () => {\n const { opportunities, userId } = state;\n if (opportunities.length === 0) {\n return { cachedCards: new Map(), uncachedOpportunities: [] };\n }\n\n if (state.noCache) {\n checkPresenterCacheLog.verbose('noCache=true, skipping cache');\n return { cachedCards: new Map(), uncachedOpportunities: opportunities };\n }\n\n try {\n // Negotiating cards are templated (no LLM call) and their text\n // depends on the live turn count, which changes between requests\n // without changing the opportunity status. Skip cache entirely\n // for them so each render reflects the current turn.\n //\n // For all other statuses, include status in the key so status\n // transitions (e.g. negotiating → pending) don't serve stale cards.\n const cacheable = opportunities.filter((opp) => opp.status !== 'negotiating');\n const liveNegotiating = opportunities.filter((opp) => opp.status === 'negotiating');\n\n const keys = cacheable.map(\n (opp) => `home:card:${opp.id}:${opp.status}:${userId}`\n );\n const results = keys.length > 0 ? await this.cache.mget<HomeCardItem>(keys) : [];\n\n const cachedCards = new Map<string, HomeCardItem>();\n const uncachedOpportunities: typeof opportunities = [...liveNegotiating];\n\n for (let i = 0; i < cacheable.length; i++) {\n const cached = results[i];\n if (cached) {\n const originalIndex = opportunities.indexOf(cacheable[i]);\n // Stamp the live status: pre-status cache entries lack the field,\n // and the key already guarantees it matches the current status.\n const deprioritizedReason = poolQuestionsRanking() === 'on'\n ? latestPoolDemotionDetail((cacheable[i] as { metadata?: Record<string, unknown> | null }).metadata)\n : undefined;\n cachedCards.set(cacheable[i].id, {\n ...cached,\n status: cacheable[i].status,\n deprioritizedReason,\n _cardIndex: originalIndex,\n });\n } else {\n uncachedOpportunities.push(cacheable[i]);\n }\n }\n\n checkPresenterCacheLog.verbose('', {\n total: opportunities.length,\n cacheHits: cachedCards.size,\n cacheMisses: uncachedOpportunities.length,\n });\n\n return { cachedCards, uncachedOpportunities };\n } catch (e) {\n checkPresenterCacheLog.warn('cache unavailable, skipping', { error: e });\n return { cachedCards: new Map(), uncachedOpportunities: opportunities };\n }\n });\n };\n\n const shouldGenerateCards = (state: typeof HomeGraphState.State): string => {\n if (state.uncachedOpportunities.length > 0) {\n return 'generate';\n }\n logger.verbose('All presenter results cached, skipping generation');\n return 'skip';\n };\n\n const generateCardTextNode = async (state: typeof HomeGraphState.State) => {\n return timed(\"HomeGraph.generateCardText\", async () => {\n const opportunities = state.uncachedOpportunities.length > 0\n ? state.uncachedOpportunities\n : state.opportunities;\n generateCardTextLog.verbose('entry', { opportunitiesLength: opportunities.length, userId: state.userId });\n if (opportunities.length === 0) {\n generateCardTextLog.verbose('exit', { totalOpportunities: 0, totalSections: 0 });\n return { cards: [], agentTimings: [], meta: { totalOpportunities: 0, totalSections: 0 } };\n }\n const db = this.database as PresenterDatabase & HomeGraphDb;\n const cards: HomeCardItem[] = [];\n const relevantActorIds = new Set<string>();\n for (const opp of opportunities) {\n for (const a of opp.actors) {\n if (a.userId) relevantActorIds.add(a.userId);\n }\n }\n\n const userEntries = await Promise.all(\n Array.from(relevantActorIds).map(async (userId) => {\n try {\n const user = await this.database.getUser(userId);\n return [userId, user ?? null] as const;\n } catch {\n return [userId, null] as const;\n }\n })\n );\n const userMap = new Map(userEntries);\n\n const oppIndexMap = new Map(\n state.opportunities.map((opp, idx) => [opp.id, idx])\n );\n\n const agentTimingsAccum: DebugMetaAgent[] = [];\n\n for (let i = 0; i < opportunities.length; i += PRESENTATION_CONCURRENCY) {\n const chunk = opportunities.slice(i, i + PRESENTATION_CONCURRENCY);\n const chunkCards = await Promise.all(\n chunk.map(async (opportunity, offset) => {\n const cardIndex = oppIndexMap.get(opportunity.id) ?? (i + offset);\n const viewerActor = opportunity.actors.find((a) => a.userId === state.userId);\n const viewerRole = viewerActor?.role ?? 'party';\n const isIntroducer = viewerRole === 'introducer';\n const preferredActor = pickDisplayCounterpartActor(opportunity, state.userId)\n ?? opportunity.actors.find((a) => a.userId !== state.userId && a.role !== 'introducer');\n const actorWithProfile = opportunity.actors.find(\n (a) => a.userId !== state.userId && a.role !== 'introducer' && !!userMap.get(a.userId)\n );\n const introducer = opportunity.actors.find((a) => a.role === 'introducer');\n let otherActor = (preferredActor && userMap.get(preferredActor.userId))\n ? preferredActor\n : (actorWithProfile ?? preferredActor);\n // When the only other participant is the introducer (no separate party), use introducer as display counterpart so the card shows a name instead of \"Unknown\"\n if (!otherActor && introducer && introducer.userId !== state.userId && introducer.userId) {\n otherActor = { userId: introducer.userId, role: introducer.role };\n }\n const otherUser = otherActor ? userMap.get(otherActor.userId) ?? null : null;\n const introducerCounterparts = opportunity.actors.filter(\n (a) => a.userId !== state.userId && a.role !== 'introducer'\n );\n // Deduplicate by userId — actors array can contain multiple rows per user\n // (e.g. from different intents), which would produce repeated names.\n const uniqueCounterpartIds = [...new Set(introducerCounterparts.map((a) => a.userId))];\n const participantNames = uniqueCounterpartIds\n .map((uid) => userMap.get(uid)?.name ?? 'Unknown')\n .sort();\n // When secondPartyData will be present (2+ counterparts), use single counterpart name\n // because the frontend arrow layout renders \"card.name → secondParty.name\".\n // Using the joined \"A ↔ B\" format here would produce redundant \"A ↔ B → B\".\n // Only use the joined format when there is a single counterpart (no arrow layout).\n const willHaveSecondParty = isIntroducer && uniqueCounterpartIds.length > 1;\n let userName = isIntroducer && participantNames.length > 0 && !willHaveSecondParty\n ? participantNames.join(' ↔ ')\n : (otherUser?.name ?? 'Unknown');\n // Fallback to profile identity name when users.name is missing (e.g. profile has display name, users row does not)\n if ((userName === 'Unknown' || !userName?.trim()) && otherActor?.userId && db.getProfile) {\n const profile = await db.getProfile(otherActor.userId).catch((err) => {\n logger.debug('getProfile fallback failed', { otherActorUserId: otherActor.userId, error: err });\n return null;\n });\n const profileName = profile?.identity?.name?.trim();\n if (profileName) userName = profileName;\n }\n // Unresolvable display counterpart (deleted user: no users row, no\n // profile fallback). Drop the card entirely instead of rendering an\n // \"Unknown\" placeholder: such cards are unusable, excluded from the\n // presenter cache (see cachePresenterResults), and would otherwise\n // trigger a fresh presenter LLM call on every request — a permanent\n // cache miss that keeps the whole feed slow (~9s per load).\n if (userName === 'Unknown' || !userName?.trim()) {\n logger.verbose('[HomeGraph:generateCardText] dropping card with unresolvable counterpart', {\n opportunityId: opportunity.id,\n otherActorUserId: otherActor?.userId,\n });\n return null;\n }\n const userAvatar = otherUser?.avatar ?? null;\n // Shared sanitization standard (UUID strip, viewer-centric rewrite,\n // boundary truncation) — raw reasoning must never render verbatim.\n const reasoningSnippet = safeFallbackSummary(\n typeof opportunity.interpretation?.reasoning === 'string'\n ? opportunity.interpretation.reasoning\n : '',\n {\n counterpartName: userName !== 'Unknown' ? userName : undefined,\n maxChars: MAX_REASONING_SNIPPET_LENGTH,\n emptyText: 'A promising connection.',\n },\n );\n\n // Build secondParty for introducer arrow layout (the party that isn't the display counterpart)\n let secondPartyData: { name: string; avatar?: string | null; userId?: string } | undefined;\n if (isIntroducer && introducerCounterparts.length > 1 && otherActor) {\n const secondActor = introducerCounterparts.find((a) => a.userId !== otherActor.userId);\n if (secondActor) {\n const secondUser = userMap.get(secondActor.userId) ?? null;\n secondPartyData = {\n name: secondUser?.name ?? 'Unknown',\n avatar: secondUser?.avatar ?? null,\n userId: secondActor.userId,\n };\n }\n }\n\n const isCounterpartGhost = otherUser?.isGhost ?? false;\n // Skeleton presentation: return an identity-only card without the\n // presenter LLM or negotiation-context load. Name resolution and\n // the unresolvable-counterpart drop above still apply, so the card\n // set matches what the follow-up full request will return.\n if (state.presentation === 'skeleton') {\n return {\n opportunityId: opportunity.id,\n status: opportunity.status,\n userId: otherActor?.userId ?? '',\n name: userName,\n avatar: userAvatar,\n mainText: '',\n cta: '',\n primaryActionLabel: getPrimaryActionLabel(viewerRole),\n secondaryActionLabel: SECONDARY_ACTION_LABEL,\n mutualIntentsLabel: isIntroducer ? 'Connector match' : 'Shared interests',\n viewerRole,\n isGhost: isCounterpartGhost,\n ...(secondPartyData ? { secondParty: secondPartyData } : {}),\n presentationPending: true,\n _cardIndex: cardIndex,\n } satisfies HomeCardItem;\n }\n const isPendingIntroducerFallback = isIntroducer && opportunity.status !== 'latent';\n const fallbackCard = (): HomeCardItem => ({\n opportunityId: opportunity.id,\n status: opportunity.status,\n userId: otherActor?.userId ?? '',\n name: userName,\n avatar: userAvatar,\n mainText: reasoningSnippet,\n cta: isIntroducer\n ? (isPendingIntroducerFallback ? 'Share this introduction to get things started.' : 'Take a look and decide if this is a good match.')\n : 'Take a look and decide whether to reach out.',\n primaryActionLabel: getPrimaryActionLabel(viewerRole),\n secondaryActionLabel: SECONDARY_ACTION_LABEL,\n mutualIntentsLabel: isIntroducer ? 'Connector match' : 'Shared interests',\n narratorChip: isIntroducer\n ? { name: 'You', text: 'Worth a look.', userId: state.userId }\n : { name: 'Index', text: 'Worth a look.' },\n viewerRole,\n isGhost: isCounterpartGhost,\n ...(secondPartyData ? { secondParty: secondPartyData } : {}),\n _cardIndex: cardIndex,\n });\n\n try {\n const [ctx, negotiationContext] = await Promise.all([\n gatherPresenterContext(\n db,\n opportunity,\n state.userId,\n otherActor?.userId,\n ),\n loadNegotiationContext(db, opportunity.id, opportunity.status),\n ]);\n const homeInput = {\n ...ctx,\n mutualIntentCount: undefined,\n opportunityStatus: opportunity.status,\n ...(negotiationContext ? { negotiationContext } : {}),\n };\n const _traceEmitterPresenter = requestContext.getStore()?.traceEmitter;\n const presenterStart = Date.now();\n _traceEmitterPresenter?.({ type: \"agent_start\", name: \"opportunity-presenter\" });\n const presentation = await presenter.presentHomeCard(homeInput);\n const _presenterDuration = Date.now() - presenterStart;\n agentTimingsAccum.push({ name: 'opportunity.presenter', durationMs: _presenterDuration });\n _traceEmitterPresenter?.({ type: \"agent_end\", name: \"opportunity-presenter\", durationMs: _presenterDuration, summary: `Presented: ${userName}` });\n let narratorChip: { name: string; text: string; avatar?: string | null; userId?: string } | undefined;\n // Only show a person as narrator when they are the introducer and not the display counterpart\n // (bad data can have same user as introducer and party, e.g. \"Amina introduced you to Amina\")\n const introducerIsCounterpart = introducer && otherActor && introducer.userId === otherActor.userId;\n if (introducer && introducer.userId !== state.userId && !introducerIsCounterpart) {\n const introUser = userMap.get(introducer.userId) ?? null;\n const narratorName = introUser?.name ?? 'Someone';\n narratorChip = {\n name: narratorName,\n text: stripLeadingNarratorName(presentation.narratorRemark, narratorName),\n avatar: introUser?.avatar ?? null,\n userId: introducer.userId,\n };\n } else if (introducer?.userId === state.userId) {\n narratorChip = { name: 'You', text: presentation.narratorRemark, userId: state.userId };\n } else {\n narratorChip = { name: 'Index', text: presentation.narratorRemark };\n }\n return {\n opportunityId: opportunity.id,\n status: opportunity.status,\n userId: otherActor?.userId ?? '',\n name: userName,\n avatar: userAvatar,\n mainText: presentation.personalizedSummary,\n cta: presentation.suggestedAction,\n headline: presentation.headline,\n primaryActionLabel: getPrimaryActionLabel(viewerRole),\n secondaryActionLabel: SECONDARY_ACTION_LABEL,\n mutualIntentsLabel: presentation.mutualIntentsLabel,\n narratorChip,\n viewerRole,\n isGhost: isCounterpartGhost,\n ...(secondPartyData ? { secondParty: secondPartyData } : {}),\n _cardIndex: cardIndex,\n } satisfies HomeCardItem;\n } catch (e) {\n logger.warn('HomeGraph presenter failed for opportunity', { opportunityId: opportunity.id, error: e });\n return fallbackCard();\n }\n })\n );\n cards.push(...chunkCards.filter((c): c is HomeCardItem => c !== null));\n }\n generateCardTextLog.verbose('exit', { totalOpportunities: state.opportunities.length, totalSections: 0 });\n return {\n cards,\n agentTimings: agentTimingsAccum,\n meta: { totalOpportunities: state.opportunities.length, totalSections: 0 },\n };\n });\n };\n\n const cachePresenterResultsNode = async (state: typeof HomeGraphState.State) => {\n return timed(\"HomeGraph.cachePresenterResults\", async () => {\n const { cards, cachedCards, userId, opportunities } = state;\n const liveById = new Map(opportunities.map((opportunity) => [opportunity.id, opportunity]));\n const cardsWithAdjustments = cards.map((card) => {\n const opportunity = liveById.get(card.opportunityId);\n const deprioritizedReason = poolQuestionsRanking() === 'on'\n ? latestPoolDemotionDetail((opportunity as { metadata?: Record<string, unknown> | null } | undefined)?.metadata)\n : undefined;\n return { ...card, deprioritizedReason };\n });\n\n // Only cache cards that weren't already from cache\n const newCards = cardsWithAdjustments.filter((card) => !cachedCards.has(card.opportunityId));\n const statusById = new Map(opportunities.map((opp) => [opp.id, opp.status]));\n\n try {\n await Promise.all(\n newCards.map((card) => {\n const status = statusById.get(card.opportunityId);\n // Skip persisting negotiating cards — see read-side note.\n if (!status || status === 'negotiating') return Promise.resolve();\n // Never cache skeleton cards — they carry no presenter text and\n // would otherwise be served as \"complete\" for the full TTL.\n if (card.presentationPending) return Promise.resolve();\n // Skip caching cards with unresolved names — transient DB failures\n // would persist \"Unknown\" placeholders for the full TTL.\n if (!card.name || card.name === 'Unknown') return Promise.resolve();\n return this.cache.set(\n `home:card:${card.opportunityId}:${status}:${userId}`,\n card,\n { ttl: HOME_CACHE_TTL }\n );\n })\n );\n } catch (e) {\n cachePresenterResultsLog.warn('cache write failed, continuing', { error: e });\n }\n\n // Merge cached cards into full card list\n const allCards: HomeCardItem[] = [...cardsWithAdjustments];\n for (const [oppId, cachedCard] of cachedCards) {\n if (!cardsWithAdjustments.some((card) => card.opportunityId === oppId)) {\n allCards.push(cachedCard);\n }\n }\n\n // Re-sort by _cardIndex to maintain original ordering\n allCards.sort((a, b) => a._cardIndex - b._cardIndex);\n\n cachePresenterResultsLog.verbose('', {\n newlyCached: newCards.length,\n totalCards: allCards.length,\n });\n\n return {\n cards: allCards,\n meta: { totalOpportunities: state.opportunities.length, totalSections: 0 },\n };\n });\n };\n\n const checkCategorizerCacheNode = async (state: typeof HomeGraphState.State) => {\n return timed(\"HomeGraph.checkCategorizerCache\", async () => {\n if (state.cards.length === 0) {\n return { categoryCacheHit: false };\n }\n\n // Skeleton runs never categorize (some cards have no text to categorize\n // and the response must stay LLM-free). Ranking-enabled lifecycle views\n // also stay flat: the intent Radar flattens sections and buckets by\n // status, so dynamic categorization would erase the adjusted order on\n // the full second-phase response. Flag off retains the legacy path.\n // Chunk by MAX_ITEMS_PER_SECTION because normalizeAndSort caps sections.\n const preserveAdjustedLifecycleOrder =\n (state.statuses?.length ?? 0) > 0 && poolQuestionsRanking() === 'on';\n if (state.presentation === 'skeleton' || preserveAdjustedLifecycleOrder) {\n const sectionProposals: HomeSectionProposal[] = [];\n for (let start = 0; start < state.cards.length; start += MAX_ITEMS_PER_SECTION) {\n sectionProposals.push({\n id: `all-${sectionProposals.length + 1}`,\n title: 'All matches',\n iconName: DEFAULT_HOME_SECTION_ICON,\n itemIndices: state.cards.slice(start, start + MAX_ITEMS_PER_SECTION).map((_, i) => start + i),\n });\n }\n return { sectionProposals, categoryCacheHit: true };\n }\n\n if (state.noCache) {\n checkCategorizerCacheLog.verbose('noCache=true, skipping cache');\n return { categoryCacheHit: false };\n }\n\n try {\n const key = buildCategorizerCacheKey(state.userId, state.cards);\n\n const cached = await this.cache.get<HomeSectionProposal[]>(key);\n if (cached) {\n checkCategorizerCacheLog.verbose('cache hit');\n return { sectionProposals: cached, categoryCacheHit: true };\n }\n\n checkCategorizerCacheLog.verbose('cache miss');\n } catch (e) {\n checkCategorizerCacheLog.warn('cache unavailable, skipping', { error: e });\n }\n return { categoryCacheHit: false };\n });\n };\n\n const shouldCategorize = (state: typeof HomeGraphState.State): string => {\n if (state.categoryCacheHit) {\n logger.verbose('Categorizer results cached, skipping');\n return 'skip';\n }\n return 'categorize';\n };\n\n const categorizeDynamicallyNode = async (state: typeof HomeGraphState.State) => {\n return timed(\"HomeGraph.categorizeDynamically\", async () => {\n categorizeDynamicallyLog.verbose('entry', { cardsLength: state.cards.length });\n if (state.cards.length === 0) {\n categorizeDynamicallyLog.verbose('exit', { sectionProposalsCount: 0 });\n return { sectionProposals: [], agentTimings: [] };\n }\n const agentTimingsAccum: DebugMetaAgent[] = [];\n const categorizerInput = state.cards.map((c) => ({\n index: c._cardIndex,\n headline: c.headline,\n mainText: c.mainText,\n name: c.name,\n viewerRole: c.viewerRole === 'introducer' ? 'introducer' : undefined,\n opportunityStatus: c.viewerRole === 'introducer' ? 'pending' : undefined,\n }));\n const _traceEmitterCategorizer = requestContext.getStore()?.traceEmitter;\n const categorizerStart = Date.now();\n _traceEmitterCategorizer?.({ type: \"agent_start\", name: \"home-categorizer\" });\n const { sections } = await categorizer.categorize(categorizerInput);\n const _categorizerDuration = Date.now() - categorizerStart;\n agentTimingsAccum.push({ name: 'home.categorizer', durationMs: _categorizerDuration });\n _traceEmitterCategorizer?.({ type: \"agent_end\", name: \"home-categorizer\", durationMs: _categorizerDuration, summary: `Categorized into ${sections.length} section(s)` });\n const proposals: HomeSectionProposal[] = sections.map((s) => ({\n ...s,\n itemIndices: s.itemIndices.filter((i) => i >= 0 && i < state.cards.length),\n }));\n categorizeDynamicallyLog.verbose('exit', { sectionProposalsCount: proposals.length });\n return { sectionProposals: proposals, agentTimings: agentTimingsAccum };\n });\n };\n\n const cacheCategorizerResultsNode = async (state: typeof HomeGraphState.State) => {\n return timed(\"HomeGraph.cacheCategorizerResults\", async () => {\n if (state.categoryCacheHit || state.sectionProposals.length === 0) {\n return {};\n }\n\n try {\n const key = buildCategorizerCacheKey(state.userId, state.cards);\n\n await this.cache.set(key, state.sectionProposals, { ttl: HOME_CACHE_TTL });\n\n cacheCategorizerResultsLog.verbose('cached', {\n sectionCount: state.sectionProposals.length,\n });\n } catch (e) {\n cacheCategorizerResultsLog.warn('cache write failed, continuing', { error: e });\n }\n\n return {};\n });\n };\n\n const normalizeAndSortNode = async (state: typeof HomeGraphState.State) => {\n return timed(\"HomeGraph.normalizeAndSort\", async () => {\n const cards = state.cards;\n const proposals = state.sectionProposals;\n normalizeAndSortLog.verbose('entry', { cardsLength: cards.length, proposalsLength: proposals.length });\n if (cards.length === 0) {\n normalizeAndSortLog.verbose('exit', { totalOpportunities: 0, totalSections: 0 });\n return { sections: [], meta: { totalOpportunities: 0, totalSections: 0 } };\n }\n const usedIndices = new Set<number>();\n const sections: HomeSection[] = proposals.map((p) => {\n const iconName = resolveHomeSectionIcon(p.iconName);\n const items: HomeSectionItem[] = p.itemIndices\n .filter((i) => i >= 0 && i < cards.length && !usedIndices.has(i))\n .slice(0, MAX_ITEMS_PER_SECTION)\n .map((i) => {\n usedIndices.add(i);\n const card = cards[i];\n const { _cardIndex, ...rest } = card;\n return rest;\n });\n return {\n id: p.id,\n title: p.title,\n subtitle: p.subtitle,\n iconName,\n items,\n };\n });\n\n // Enforce category ordering: sections with connections first, then\n // connector-flow only, then expired only. This prevents the LLM\n // categorizer from placing introducer sections before connection sections.\n const sectionCategoryPriority = (section: HomeSection): number => {\n const hasConnection = section.items.some((item) => item.viewerRole !== 'introducer');\n if (hasConnection) return 0; // mixed or connection-only sections first\n const hasConnectorFlow = section.items.some((item) => item.viewerRole === 'introducer');\n if (hasConnectorFlow) return 1; // connector-flow only sections next\n return 2; // empty or expired sections last\n };\n sections.sort((a, b) => sectionCategoryPriority(a) - sectionCategoryPriority(b));\n const meta = {\n totalOpportunities: state.opportunities.length,\n totalSections: sections.length,\n };\n normalizeAndSortLog.verbose('exit', { totalOpportunities: meta.totalOpportunities, totalSections: meta.totalSections });\n return { sections, meta };\n });\n };\n\n const graph = new StateGraph(HomeGraphState)\n .addNode('loadOpportunities', loadOpportunitiesNode)\n .addNode('checkPresenterCache', checkPresenterCacheNode)\n .addNode('generateCardText', generateCardTextNode)\n .addNode('cachePresenterResults', cachePresenterResultsNode)\n .addNode('checkCategorizerCache', checkCategorizerCacheNode)\n .addNode('categorizeDynamically', categorizeDynamicallyNode)\n .addNode('cacheCategorizerResults', cacheCategorizerResultsNode)\n .addNode('normalizeAndSort', normalizeAndSortNode)\n .addEdge(START, 'loadOpportunities')\n .addEdge('loadOpportunities', 'checkPresenterCache')\n .addConditionalEdges('checkPresenterCache', shouldGenerateCards, {\n generate: 'generateCardText',\n skip: 'cachePresenterResults',\n })\n .addEdge('generateCardText', 'cachePresenterResults')\n .addEdge('cachePresenterResults', 'checkCategorizerCache')\n .addConditionalEdges('checkCategorizerCache', shouldCategorize, {\n categorize: 'categorizeDynamically',\n skip: 'normalizeAndSort',\n })\n .addEdge('categorizeDynamically', 'cacheCategorizerResults')\n .addEdge('cacheCategorizerResults', 'normalizeAndSort')\n .addEdge('normalizeAndSort', END);\n\n return graph.compile();\n }\n}\n"]}
@@ -29,6 +29,8 @@ export interface HomeCardItem {
29
29
  viewerRole?: string;
30
30
  /** Whether the counterpart is a ghost (not yet onboarded) user. */
31
31
  isGhost?: boolean;
32
+ /** Template-only explanation for a pool-answer demotion (never evaluator reasoning). */
33
+ deprioritizedReason?: string;
32
34
  /** Second party in introducer arrow layout. Present when viewerRole is 'introducer'. */
33
35
  secondParty?: {
34
36
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"feed.state.d.ts","sourceRoot":"/","sources":["opportunity/feed/feed.state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;AACpG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,2GAA2G;IAC3G,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,wFAAwF;IACxF,kBAAkB,EAAE,MAAM,CAAC;IAC3B,2FAA2F;IAC3F,YAAY,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACvF,kGAAkG;IAClG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wFAAwF;IACxF,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACxE;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,sCAAsC;IACtC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,6DAA6D;AAC7D,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc;;;;;;IAsBzB,gEAAgE;;IAMhE;;;;;OAKG;;IAMH,sFAAsF;;IAMtF,yEAAyE;;IAMzE,qDAAqD;;IAMrD,+DAA+D;;IAM/D,mCAAmC;;IAMnC,6EAA6E;;IAM7E,yEAAyE;;IAMzE,uDAAuD;;;IAWvD,kEAAkE;;4BAC3B,MAAM;uBAAiB,MAAM;;4BAA7B,MAAM;uBAAiB,MAAM;;4BAA7B,MAAM;uBAAiB,MAAM;;IAKpE,sEAAsE;;EAKtE,CAAC"}
1
+ {"version":3,"file":"feed.state.d.ts","sourceRoot":"/","sources":["opportunity/feed/feed.state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;AACpG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,2GAA2G;IAC3G,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,wFAAwF;IACxF,kBAAkB,EAAE,MAAM,CAAC;IAC3B,2FAA2F;IAC3F,YAAY,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACvF,kGAAkG;IAClG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wFAAwF;IACxF,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,wFAAwF;IACxF,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACxE;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,sCAAsC;IACtC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,6DAA6D;AAC7D,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc;;;;;;IAsBzB,gEAAgE;;IAMhE;;;;;OAKG;;IAMH,sFAAsF;;IAMtF,yEAAyE;;IAMzE,qDAAqD;;IAMrD,+DAA+D;;IAM/D,mCAAmC;;IAMnC,6EAA6E;;IAM7E,yEAAyE;;IAMzE,uDAAuD;;;IAWvD,kEAAkE;;4BAC3B,MAAM;uBAAiB,MAAM;;4BAA7B,MAAM;uBAAiB,MAAM;;4BAA7B,MAAM;uBAAiB,MAAM;;IAKpE,sEAAsE;;EAKtE,CAAC"}