{"version":3,"file":"public-tools-DScJ1mRk.mjs","names":["GRAPH_QUERY_BATCH_TIMEOUT_SECONDS","GRAPH_QUERY_BATCH_REQUEST_TIMEOUT_MS","clampInt","escapeCypherString","textFromToolResult","parseGraphBatchResult","topologyGraphQuery","callGraphBatch","flowEdgeMap","pathNodeMap","edgeKey","numberValue","isExchangeFlag","stringArrayValue","uniqueStrings","hasExactExchangeLabel","htmlEscape"],"sources":["../src/investigation/risk-level.ts","../src/investigation/trace-funds.ts","../src/investigation/public-tools.ts"],"sourcesContent":["/**\n * Risk-level normalization shared by the AML tools and graph payload builders.\n *\n * The Chain Insights Graph serves the ML verdict verbatim, which historically\n * mixed cases (HIGH vs high) and — since the calibrated-scoring release —\n * includes an explicit abstention band: risk_level = UNSCORED means the model\n * had too little labeled graph context to stand behind a band. UNSCORED is a\n * \"no stance\" state and must never be rendered or reasoned about as low risk.\n */\n\nexport const RISK_SEVERITIES = ['low', 'medium', 'high', 'critical'] as const\nexport const UNSCORED_RISK_LEVEL = 'unscored'\n\n/** Lowercased, trimmed risk level; undefined for empty/unrecognized values. */\nexport function normalizeRiskLevel(value: unknown): string | undefined {\n  if (typeof value !== 'string') return undefined\n  const normalized = value.trim().toLowerCase()\n  if (!normalized) return undefined\n  if (normalized === UNSCORED_RISK_LEVEL) return UNSCORED_RISK_LEVEL\n  if ((RISK_SEVERITIES as readonly string[]).includes(normalized)) return normalized\n  return undefined\n}\n\n/** True when the ML verdict explicitly abstained (no stance, not low). */\nexport function isUnscoredRiskLevel(value: unknown): boolean {\n  return normalizeRiskLevel(value) === UNSCORED_RISK_LEVEL\n}\n\n/**\n * Severity ordering for comparisons: low(0) < medium(1) < high(2) <\n * critical(3). Unknown/unscored values rank -1 — they never win a\n * severity comparison, they abstain from it.\n */\nexport function riskSeverityRank(value: unknown): number {\n  const normalized = normalizeRiskLevel(value)\n  if (!normalized || normalized === UNSCORED_RISK_LEVEL) return -1\n  return (RISK_SEVERITIES as readonly string[]).indexOf(normalized)\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises'\nimport path from 'node:path'\nimport type { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport type { ContentBlock } from '@modelcontextprotocol/sdk/types.js'\nimport type { InvestigatorConfig } from '../config/schema.js'\nimport { normalizeGraphPayload } from '../viz/graph-normalizer.js'\nimport { normalizeRiskLevel } from './risk-level.js'\nimport { workspaceOutputPaths, type WorkspaceOutputPaths } from '../workspace/output-root.js'\n\ntype RemoteToolResult = {\n  content?: ContentBlock[]\n  isError?: boolean\n}\n\nexport type TopologyScope = 'live_topology' | 'archive_topology'\nexport const DEFAULT_TOPOLOGY_SCOPE: TopologyScope = 'live_topology'\n\nexport interface TraceActivityWindow {\n  fromMs: number\n  toMs?: number\n}\n\nexport interface TraceFundsOptions {\n  seedAddress: string\n  network: string\n  maxHops?: number\n  perAddressLimit?: number\n  minAmountSum?: number\n  activityWindow?: TraceActivityWindow\n  includeDepositTraceback?: boolean\n  evidenceSource?: string\n  writeArtifacts?: boolean\n  topologyScope?: TopologyScope\n}\n\nexport interface TraceFlow {\n  hop: number\n  src: string\n  dst: string\n  amount_usd_sum: number\n  tx_count?: number\n  first_tx_id?: string\n  last_tx_id?: string\n  first_seen_timestamp?: number\n  last_seen_timestamp?: number\n  src_labels?: string[]\n  dst_labels?: string[]\n  src_node?: GraphNodeMetadata\n  dst_node?: GraphNodeMetadata\n  terminal_exchange: boolean\n}\n\nexport interface TraceFundsResult {\n  summaryText: string\n  compactEvidence: Record<string, unknown>\n  graphData: Record<string, unknown>\n  files: {\n    schema: string\n    compactEvidence: string\n    graph: string\n    graphHtml: string\n    table: string\n    tableHtml: string\n    report: string\n  }\n  continuation: {\n    nextHopAddresses: string[]\n    depositAddresses: string[]\n    exchangeAddresses: string[]\n    hint: string\n  }\n  addressMap: Record<string, string>\n  tracebackWarnings: string[]\n}\n\ninterface TraceDeposit {\n  address: string\n  exchangeAddress: string\n  exchangeLabels?: string[]\n  exchangeNode?: GraphNodeMetadata\n  amount_usd_sum?: number\n  hops: number\n  path: string[]\n  pathNodes?: GraphNodeMetadata[]\n}\n\ninterface SourceMatch {\n  deposit_address: string\n  source_exchange: string\n  source_labels?: string[]\n  sourceNode?: GraphNodeMetadata\n  hops: number\n  path: string[]\n  pathNodes?: GraphNodeMetadata[]\n}\n\ninterface ReverseLead {\n  address: string\n  labels?: string[]\n  node?: GraphNodeMetadata\n  deposit_address: string\n  amount_usd?: number\n  reason: string\n}\n\ninterface GraphNodeMetadata {\n  address: string\n  labels?: string[]\n  system_labels?: string[]\n  addresses?: string[]\n  risk_score?: number\n  risk_level?: string\n  is_exchange?: boolean\n}\n\nclass AliasTracker {\n  private readonly byAddress = new Map<string, string>()\n  private readonly byAlias = new Map<string, string>()\n  private readonly counters = new Map<string, number>()\n\n  assign(address: string, prefix: string): string {\n    const existing = this.byAddress.get(address)\n    if (existing) return existing\n    const next = (this.counters.get(prefix) ?? 0) + 1\n    this.counters.set(prefix, next)\n    const alias = `${prefix}${next}`\n    this.byAddress.set(address, alias)\n    this.byAlias.set(alias, address)\n    return alias\n  }\n\n  alias(address: string): string | undefined {\n    return this.byAddress.get(address)\n  }\n\n  addressMap(): Record<string, string> {\n    return Object.fromEntries([...this.byAlias.entries()].sort(([a], [b]) => a.localeCompare(b, undefined, { numeric: true })))\n  }\n\n  compactAddressMap(maxIntermediaries = 20, maxSourceExchanges = 20, maxLeads = 20): Record<string, string> {\n    const counts = new Map<string, number>()\n    const entries = [...this.byAlias.entries()].filter(([alias]) => {\n      const prefix = alias.slice(0, 1)\n      if (['V', 'D', 'E'].includes(prefix)) return true\n      const next = (counts.get(prefix) ?? 0) + 1\n      counts.set(prefix, next)\n      if (prefix === 'I') return next <= maxIntermediaries\n      if (prefix === 'X') return next <= maxSourceExchanges\n      if (prefix === 'L') return next <= maxLeads\n      return true\n    })\n    return Object.fromEntries(entries.sort(([a], [b]) => a.localeCompare(b, undefined, { numeric: true })))\n  }\n}\n\ninterface ParsedGraphBatch {\n  facts?: {\n    queries?: Array<{\n      id?: string\n      ok?: boolean\n      results?: Array<Record<string, unknown>>\n      error?: string\n    }>\n  }\n}\n\nconst GRAPH_QUERY_BATCH_TIMEOUT_SECONDS = 10\nconst GRAPH_QUERY_BATCH_REQUEST_TIMEOUT_MS = 5 * 60 * 1000\n\nconst SCHEMA_QUERY_SET = [\n  {\n    id: 'node_labels',\n    query: 'MATCH (n:Identity) RETURN \"Identity\" AS node_label, count(n) AS sample_count LIMIT 1',\n  },\n  {\n    id: 'relationship_types',\n    query: 'MATCH (:Identity)-[r:FLOWS_TO]->(:Identity) RETURN \"FLOWS_TO\" AS rel_name, count(r) AS sample_count LIMIT 1',\n  },\n  {\n    id: 'identity_property_keys',\n    query: 'MATCH (n:Identity) RETURN \"identity_id\" AS property_key, count(n) AS sample_count LIMIT 1',\n  },\n  {\n    id: 'flows_to_property_keys',\n    query: 'MATCH (:Identity)-[r:FLOWS_TO]->(:Identity) RETURN \"amount_usd_sum\" AS property_key, count(r) AS sample_count LIMIT 1',\n  },\n]\n\nfunction clampInt(value: number | undefined, fallback: number, min: number, max: number): number {\n  if (!Number.isFinite(value)) return fallback\n  return Math.max(min, Math.min(max, Math.trunc(value as number)))\n}\n\nfunction escapeCypherString(value: string): string {\n  return value.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"')\n}\n\nfunction sanitizeSegment(value: string): string {\n  const sanitized = value.toLowerCase().replace(/[^a-z0-9_-]+/g, '-').replace(/(^-|-$)/g, '').slice(0, 80)\n  return sanitized || 'trace'\n}\n\nasync function ensureDirs(paths: WorkspaceOutputPaths): Promise<void> {\n  await mkdir(paths.schemaDir, { recursive: true, mode: 0o700 })\n  await mkdir(paths.reportsRoot, { recursive: true, mode: 0o700 })\n  await mkdir(paths.reportGraphsRoot, { recursive: true, mode: 0o700 })\n  await mkdir(paths.reportTablesRoot, { recursive: true, mode: 0o700 })\n  await mkdir(paths.logsRoot, { recursive: true, mode: 0o700 })\n}\n\nfunction textFromToolResult(result: RemoteToolResult): string {\n  return (result.content ?? [])\n    .filter((item): item is Extract<ContentBlock, { type: 'text' }> => item.type === 'text')\n    .map((item) => item.text)\n    .join('\\n')\n}\n\nfunction parseGraphBatchResult(result: RemoteToolResult): ParsedGraphBatch {\n  const text = textFromToolResult(result).trim()\n  if (!text) throw new Error('graph_query_batch returned no text content')\n  const parsed = JSON.parse(text) as ParsedGraphBatch\n  if (!parsed.facts?.queries) throw new Error('graph_query_batch response did not include facts.queries')\n  return parsed\n}\n\nfunction topologyGraphQuery(query: string, scope: TopologyScope = DEFAULT_TOPOLOGY_SCOPE): string {\n  const trimmed = query.trim()\n  if (/^USE\\s+/i.test(trimmed)) return trimmed\n  return `USE ${scope} ${trimmed}`\n}\n\nasync function callGraphBatch(\n  remoteClient: Client,\n  network: string,\n  queries: Array<{ id: string; query: string }>,\n  topologyScope: TopologyScope = DEFAULT_TOPOLOGY_SCOPE,\n): Promise<ParsedGraphBatch> {\n  const result = await remoteClient.callTool(\n    {\n      name: 'graph_query_batch',\n      arguments: {\n        network,\n        queries: queries.map((query) => ({\n          ...query,\n          query: topologyGraphQuery(query.query, topologyScope),\n        })),\n        per_query_timeout_seconds: GRAPH_QUERY_BATCH_TIMEOUT_SECONDS,\n      },\n    },\n    undefined,\n    {\n      timeout: GRAPH_QUERY_BATCH_REQUEST_TIMEOUT_MS,\n      maxTotalTimeout: GRAPH_QUERY_BATCH_REQUEST_TIMEOUT_MS,\n    },\n  ) as RemoteToolResult\n  if (result.isError) throw new Error(textFromToolResult(result) || 'graph_query_batch failed')\n  return parseGraphBatchResult(result)\n}\n\nfunction resultsFor(batch: ParsedGraphBatch, id: string): Array<Record<string, unknown>> {\n  const query = batch.facts?.queries?.find((entry) => entry.id === id)\n  if (!query) return []\n  if (query.ok === false) throw new Error(query.error || `Query failed: ${id}`)\n  return query.results ?? []\n}\n\nfunction schemaFromGraphBatch(network: string, batch: ParsedGraphBatch): Record<string, unknown> {\n  return {\n    schema: 'chain-insights.runtime_graph_schema.v1',\n    network,\n    source: 'graph_query_batch',\n    node_labels: resultsFor(batch, 'node_labels'),\n    relationship_types: resultsFor(batch, 'relationship_types'),\n    identity_property_keys: resultsFor(batch, 'identity_property_keys').map((row) => row['property_key']),\n    flows_to_property_keys: resultsFor(batch, 'flows_to_property_keys').map((row) => row['property_key']),\n    recommended_flow_projection: [\n      'src.identity_id AS src',\n      'dst.identity_id AS dst',\n      'r.amount_usd_sum AS amount_usd_sum',\n      'r.tx_count AS tx_count',\n      'r.first_seen_timestamp AS first_seen_timestamp',\n      'r.last_seen_timestamp AS last_seen_timestamp',\n      'r.first_tx_id AS first_tx_id',\n      'r.last_tx_id AS last_tx_id',\n      'dst.labels AS dst_labels',\n    ],\n  }\n}\n\nasync function loadOrCaptureTopologySchema(\n  remoteClient: Client,\n  paths: WorkspaceOutputPaths,\n  network: string,\n): Promise<{ schema: Record<string, unknown>; filePath: string }> {\n  const filePath = path.join(paths.schemaDir, `${sanitizeSegment(network)}.graph-schema.json`)\n  try {\n    return { schema: JSON.parse(await readFile(filePath, 'utf8')) as Record<string, unknown>, filePath }\n  } catch (err) {\n    if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err\n  }\n\n  const batch = await callGraphBatch(\n    remoteClient,\n    network,\n    SCHEMA_QUERY_SET,\n  )\n  const schema = schemaFromGraphBatch(network, batch)\n  await writeFile(filePath, JSON.stringify(schema, null, 2) + '\\n', { mode: 0o600 })\n  return { schema, filePath }\n}\n\nfunction flowEdgeMap(variableName: string): string {\n  return `{amount_usd_sum: ${variableName}.amount_usd_sum, tx_count: ${variableName}.tx_count, first_seen_timestamp: ${variableName}.first_seen_timestamp, last_seen_timestamp: ${variableName}.last_seen_timestamp, first_tx_id: ${variableName}.first_tx_id, last_tx_id: ${variableName}.last_tx_id}`\n}\n\nfunction pathNodeMap(variableName: string, topologyScope: TopologyScope): string {\n  // risk_score/risk_level are a live_topology-only \"slim live risk verdict\" on\n  // :Identity (see data-pipeline ops/memgql/README.md); the archive_topology\n  // StarRocks mapping never defines them, so projecting them there hard-errors\n  // the whole query instead of nulling gracefully.\n  const riskFields = topologyScope === 'archive_topology' ? '' : `, risk_score: ${variableName}.risk_score, risk_level: ${variableName}.risk_level`\n  return `{address: ${variableName}.identity_id, labels: ${variableName}.labels, system_labels: ${variableName}.labels, is_exchange: ${variableName}.is_exchange${riskFields}}`\n}\n\nexport function activityWindowPredicates(edgeVariables: string[], window: TraceActivityWindow | undefined): string[] {\n  if (!window) return []\n  return edgeVariables.map((edgeVariable) => {\n    const from = `(${edgeVariable}.first_seen_timestamp >= ${window.fromMs} OR ${edgeVariable}.last_seen_timestamp >= ${window.fromMs})`\n    const to = window.toMs !== undefined ? ` AND ${edgeVariable}.first_seen_timestamp <= ${window.toMs}` : ''\n    return `${from}${to}`\n  })\n}\n\nfunction forwardExchangeQueries(address: string, limit: number, minAmountSum: number, maxHops: number, topologyScope: TopologyScope, activityWindow?: TraceActivityWindow): Array<{ id: string; query: string }> {\n  return Array.from({ length: maxHops }, (_, index) => forwardExchangeQueryAtDepth(address, limit, minAmountSum, index + 1, topologyScope, activityWindow))\n}\n\nfunction forwardExchangeQueryAtDepth(address: string, limit: number, minAmountSum: number, depth: number, topologyScope: TopologyScope, activityWindow?: TraceActivityWindow): { id: string; query: string } {\n  const intermediateVariables = Array.from({ length: Math.max(depth - 1, 0) }, (_, index) => `n${index + 1}`)\n  const nodeVariables = ['s', ...intermediateVariables, 't']\n  const edgeVariables = Array.from({ length: depth }, (_, index) => `r${index + 1}`)\n  const relationshipChain = edgeVariables.map((edgeVariable, index) => {\n    const targetVariable = index === edgeVariables.length - 1 ? 't' : intermediateVariables[index]!\n    return `-[${edgeVariable}:FLOWS_TO]->(${targetVariable}:Identity)`\n  }).join('')\n  const amountPredicates = edgeVariables.map((edgeVariable) => `${edgeVariable}.amount_usd_sum IS NOT NULL${minAmountSum > 0 ? ` AND ${edgeVariable}.amount_usd_sum >= ${minAmountSum}` : ''}`)\n  const nonTerminalPredicates = ['s', ...intermediateVariables].map((nodeVariable) => `${nodeVariable}.is_exchange IS NULL`)\n  // Compare identity_id (property), not the node reference: StarRocks GQL\n  // (archive_topology) does not support direct node-to-node comparison (s <> t\n  // / id(s) <> id(t)), only Memgraph/Cypher (live_topology) does. Property\n  // comparison is equivalent here and works on both backends.\n  const predicates = ['s.identity_id <> t.identity_id', ...nonTerminalPredicates, 't.is_exchange IS NOT NULL', ...amountPredicates, ...activityWindowPredicates(edgeVariables, activityWindow)]\n  const depositVariable = nodeVariables[nodeVariables.length - 2]!\n  return {\n    id: `forward_exchange_paths_${depth}`,\n    query: [\n      `MATCH (s:Identity {identity_id: \"${escapeCypherString(address)}\"})${relationshipChain}`,\n      `WHERE ${predicates.join(' AND ')}`,\n      `RETURN [${nodeVariables.map((nodeVariable) => `${nodeVariable}.identity_id`).join(', ')}] AS addresses, [${nodeVariables.map((nodeVariable) => `${nodeVariable}.labels`).join(', ')}] AS node_labels, [${nodeVariables.map((nodeVariable) => pathNodeMap(nodeVariable, topologyScope)).join(', ')}] AS path_nodes, [${edgeVariables.map(flowEdgeMap).join(', ')}] AS edge_props, t.identity_id AS exchange_address, t.labels AS exchange_display_labels, t.labels AS exchange_labels, t.is_exchange AS exchange_is_exchange, ${depositVariable}.identity_id AS deposit_address, ${depositVariable}.is_exchange AS deposit_is_exchange, ${depth} AS hops`,\n      'ORDER BY hops ASC',\n      `LIMIT ${limit}`,\n    ].join(' '),\n  }\n}\n\nfunction backwardSourceQueries(idPrefix: string, depositAddress: string, maxHops: number, topologyScope: TopologyScope): Array<{ id: string; query: string }> {\n  return Array.from({ length: maxHops }, (_, index) => backwardSourceQueryAtDepth(`${idPrefix}_${index + 1}`, depositAddress, index + 1, topologyScope))\n}\n\nfunction backwardSourceQueryAtDepth(id: string, depositAddress: string, depth: number, topologyScope: TopologyScope): { id: string; query: string } {\n  const intermediateVariables = Array.from({ length: Math.max(depth - 1, 0) }, (_, index) => `n${index + 1}`)\n  const nodeVariables = ['dep', ...intermediateVariables, 'source']\n  const edgeVariables = Array.from({ length: depth }, (_, index) => `r${index + 1}`)\n  const relationshipChain = edgeVariables.map((edgeVariable, index) => {\n    const targetVariable = index === edgeVariables.length - 1 ? 'source' : intermediateVariables[index]!\n    return `<-[${edgeVariable}:FLOWS_TO]-(${targetVariable}:Identity)`\n  }).join('')\n  const intermediatePredicates = intermediateVariables.map((nodeVariable) => `${nodeVariable}.is_exchange IS NULL`)\n  return {\n    id,\n    query: [\n      `MATCH (dep:Identity {identity_id: \"${escapeCypherString(depositAddress)}\"})`,\n      `MATCH (dep)${relationshipChain}`,\n      `WHERE source.identity_id <> dep.identity_id AND source.is_exchange IS NOT NULL${intermediatePredicates.length > 0 ? ` AND ${intermediatePredicates.join(' AND ')}` : ''}`,\n      `RETURN dep.identity_id AS deposit_address, source.identity_id AS source_exchange, source.labels AS source_display_labels, source.labels AS source_labels, ${depth} AS hops, [${nodeVariables.map((nodeVariable) => `${nodeVariable}.identity_id`).join(', ')}] AS addresses, [${nodeVariables.map((nodeVariable) => `${nodeVariable}.labels`).join(', ')}] AS node_labels, [${nodeVariables.map((nodeVariable) => pathNodeMap(nodeVariable, topologyScope)).join(', ')}] AS path_nodes`,\n      'LIMIT 20',\n    ].join(' '),\n  }\n}\n\nfunction reverseLeadsQuery(depositAddresses: string[], topologyScope: TopologyScope): { id: string; query: string } {\n  const depositPredicates = depositAddresses.map((address) => `deposit.identity_id = \"${escapeCypherString(address)}\"`)\n  const riskFields = topologyScope === 'archive_topology' ? '' : ', sender.risk_score AS risk_score, sender.risk_level AS risk_level'\n  return {\n    id: 'reverse_1hop',\n    query: [\n      'MATCH (sender:Identity)-[r:FLOWS_TO]->(deposit:Identity)',\n      `WHERE (${depositPredicates.join(' OR ')}) AND sender.is_exchange IS NULL AND sender.identity_id <> deposit.identity_id`,\n      `RETURN DISTINCT sender.identity_id AS address, sender.labels AS display_labels, sender.labels AS system_labels${riskFields}, deposit.identity_id AS deposit_address, r.amount_usd_sum AS amount_usd`,\n      'ORDER BY r.amount_usd_sum DESC',\n      `LIMIT ${Math.max(50, depositAddresses.length * 50)}`,\n    ].join(' '),\n  }\n}\n\nfunction edgeKey(src: string, dst: string): string {\n  return `${src}\\u0000${dst}`\n}\n\nfunction directEdgePropsQuery(flows: TraceFlow[]): { id: string; query: string } | null {\n  const pairs = [...new Map(flows.map((flow) => [edgeKey(flow.src, flow.dst), { src: flow.src, dst: flow.dst }])).values()]\n  if (pairs.length === 0) return null\n  const predicates = pairs.map((pair) =>\n    `(a.identity_id = \"${escapeCypherString(pair.src)}\" AND b.identity_id = \"${escapeCypherString(pair.dst)}\")`\n  )\n  return {\n    id: 'direct_edge_props',\n    query: [\n      'MATCH (a:Identity)-[r:FLOWS_TO]->(b:Identity)',\n      `WHERE (${predicates.join(' OR ')})`,\n      'RETURN a.identity_id AS src, b.identity_id AS dst, r.amount_usd_sum AS amount_usd_sum, r.tx_count AS tx_count, r.first_tx_id AS first_tx_id, r.last_tx_id AS last_tx_id, r.first_seen_timestamp AS first_seen_timestamp, r.last_seen_timestamp AS last_seen_timestamp',\n      `LIMIT ${pairs.length}`,\n    ].join(' '),\n  }\n}\n\nfunction numberValue(value: unknown): number | undefined {\n  if (typeof value === 'number' && Number.isFinite(value)) return value\n  if (typeof value === 'string' && value.trim()) {\n    const parsed = Number(value)\n    return Number.isFinite(parsed) ? parsed : undefined\n  }\n  return undefined\n}\n\nfunction isExchangeFlag(value: unknown): boolean {\n  if (value === true) return true\n  if (value === false || value === null || value === undefined) return false\n  if (typeof value === 'string') {\n    const normalized = value.trim().toLowerCase()\n    return normalized === 'true' || normalized === '1'\n  }\n  if (typeof value === 'number') return value === 1\n  return false\n}\n\nfunction rowTerminalAmount(row: Record<string, unknown>): number | undefined {\n  const edgeProps = Array.isArray(row['edge_props']) ? row['edge_props'] as Array<Record<string, unknown>> : []\n  const terminalEdge = edgeProps[edgeProps.length - 1]\n  if (!terminalEdge) return undefined\n  return numberValue(terminalEdge['amount_usd_sum'])\n}\n\nfunction rowsMatchingMinimumAmount(rows: Array<Record<string, unknown>>, minAmountSum: number): Array<Record<string, unknown>> {\n  if (minAmountSum <= 0) return rows\n  return rows.filter((row) => (rowTerminalAmount(row) ?? 0) >= minAmountSum)\n}\n\nfunction stringArrayValue(value: unknown): string[] | undefined {\n  if (Array.isArray(value)) return value.map(String)\n  if (typeof value === 'string' && value.trim()) return [value]\n  return undefined\n}\n\nfunction uniqueStrings(values: string[] | undefined): string[] {\n  return [...new Set(values ?? [])]\n}\n\nfunction hasExactExchangeLabel(labels: string[] | undefined): boolean {\n  return (labels ?? []).some((label) => label.trim().toLowerCase() === 'exchange')\n}\n\nfunction nodeMetadataFromValue(value: unknown, fallbackAddress?: string): GraphNodeMetadata | undefined {\n  if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n    return fallbackAddress ? { address: fallbackAddress } : undefined\n  }\n  const record = value as Record<string, unknown>\n  const address = typeof record['address'] === 'string' ? record['address'] : fallbackAddress\n  if (!address) return undefined\n  return {\n    address,\n    labels: stringArrayValue(record['labels']),\n    system_labels: stringArrayValue(record['system_labels']),\n    addresses: stringArrayValue(record['member_addresses']),\n    risk_score: numberValue(record['risk_score']),\n    risk_level: normalizeRiskLevel(record['risk_level']),\n    is_exchange: isExchangeFlag(record['is_exchange']),\n  }\n}\n\nfunction isExchangeFlow(flow: TraceFlow): boolean {\n  return flow.terminal_exchange ||\n    isExchangeFlag(flow.dst_node?.is_exchange) ||\n    hasExactExchangeLabel(flow.dst_labels) ||\n    hasExactExchangeLabel(flow.dst_node?.system_labels) ||\n    hasExactExchangeLabel(flow.dst_node?.labels)\n}\n\nfunction isExchangeNode(metadata: GraphNodeMetadata | undefined, labels: string[] | undefined): boolean {\n  return isExchangeFlag(metadata?.is_exchange) ||\n    hasExactExchangeLabel(labels) ||\n    hasExactExchangeLabel(metadata?.system_labels) ||\n    hasExactExchangeLabel(metadata?.labels)\n}\n\nfunction rowTouchesExchangeBeforeTerminal(pathNodes: Array<GraphNodeMetadata | undefined>, nodeLabels: string[][], pathLength: number): boolean {\n  for (let index = 0; index < Math.max(pathLength - 1, 0); index += 1) {\n    if (isExchangeNode(pathNodes[index], nodeLabels[index])) return true\n  }\n  return false\n}\n\nfunction depositFromRow(row: Record<string, unknown>): TraceDeposit | null {\n  const pathAddresses = stringArrayValue(row['addresses']) ?? []\n  if (pathAddresses.length < 2) return null\n  const nodeLabels = Array.isArray(row['node_labels']) ? row['node_labels'].map((labels) => stringArrayValue(labels) ?? []) : []\n  const exchangeAddress = typeof row['exchange_address'] === 'string' ? row['exchange_address'] : pathAddresses[pathAddresses.length - 1]\n  const edgeProps = Array.isArray(row['edge_props']) ? row['edge_props'] as Array<Record<string, unknown>> : []\n  const terminalEdge = edgeProps[edgeProps.length - 1] ?? {}\n  const pathNodes = Array.isArray(row['path_nodes'])\n    ? row['path_nodes'].map((node, index) => nodeMetadataFromValue(node, pathAddresses[index])).filter((node): node is GraphNodeMetadata => Boolean(node))\n    : undefined\n  const depositIndex = pathAddresses.length - 2\n  const depositNode = pathNodes?.find((node) => node.address === pathAddresses[depositIndex]) ?? pathNodes?.[depositIndex]\n  if (isExchangeFlag(row['deposit_is_exchange']) || isExchangeNode(depositNode, nodeLabels[depositIndex])) return null\n  const exchangeNode = {\n    address: exchangeAddress,\n    labels: stringArrayValue(row['exchange_display_labels']),\n    system_labels: stringArrayValue(row['exchange_system_labels']) ?? stringArrayValue(row['exchange_labels']),\n    is_exchange: true,\n  }\n  return {\n    address: pathAddresses[pathAddresses.length - 2]!,\n    exchangeAddress,\n    exchangeLabels: stringArrayValue(row['exchange_labels']),\n    exchangeNode,\n    amount_usd_sum: numberValue(terminalEdge['amount_usd_sum']),\n    hops: numberValue(row['hops']) ?? pathAddresses.length - 1,\n    path: pathAddresses,\n    pathNodes,\n  }\n}\n\nfunction flowsFromForwardRows(rows: Array<Record<string, unknown>>): { flows: TraceFlow[]; deposits: TraceDeposit[] } {\n  const flows: TraceFlow[] = []\n  const deposits: TraceDeposit[] = []\n  const seenEdges = new Set<string>()\n  for (const row of rows) {\n    const pathAddresses = stringArrayValue(row['addresses']) ?? []\n    const nodeLabels = Array.isArray(row['node_labels']) ? row['node_labels'].map((labels) => stringArrayValue(labels) ?? []) : []\n    const pathNodes = Array.isArray(row['path_nodes'])\n      ? row['path_nodes'].map((node, index) => nodeMetadataFromValue(node, pathAddresses[index]))\n      : []\n    const edgeProps = Array.isArray(row['edge_props']) ? row['edge_props'] as Array<Record<string, unknown>> : []\n    if (rowTouchesExchangeBeforeTerminal(pathNodes, nodeLabels, pathAddresses.length)) continue\n    const deposit = depositFromRow(row)\n    if (deposit) deposits.push(deposit)\n    for (let index = 0; index < pathAddresses.length - 1; index += 1) {\n      const src = pathAddresses[index]!\n      const dst = pathAddresses[index + 1]!\n      const edge = edgeProps[index] ?? {}\n      const terminal = index === pathAddresses.length - 2\n      const key = `${src}->${dst}`\n      if (seenEdges.has(key)) continue\n      seenEdges.add(key)\n      flows.push({\n        hop: index + 1,\n        src,\n        dst,\n        amount_usd_sum: numberValue(edge['amount_usd_sum']) ?? 0,\n        tx_count: numberValue(edge['tx_count']),\n        first_tx_id: typeof edge['first_tx_id'] === 'string' ? edge['first_tx_id'] : undefined,\n        last_tx_id: typeof edge['last_tx_id'] === 'string' ? edge['last_tx_id'] : undefined,\n        first_seen_timestamp: numberValue(edge['first_seen_timestamp']),\n        last_seen_timestamp: numberValue(edge['last_seen_timestamp']),\n        src_labels: nodeLabels[index],\n        dst_labels: nodeLabels[index + 1],\n        src_node: pathNodes[index],\n        dst_node: pathNodes[index + 1],\n        terminal_exchange: terminal,\n      })\n    }\n  }\n  return { flows, deposits }\n}\n\nasync function hydrateDirectEdgeProps(remoteClient: Client, network: string, flows: TraceFlow[], deposits: TraceDeposit[], topologyScope: TopologyScope): Promise<void> {\n  const query = directEdgePropsQuery(flows)\n  if (!query) return\n\n  const batch = await callGraphBatch(remoteClient, network, [query], topologyScope)\n  const edgeProps = new Map<string, Record<string, unknown>>()\n  for (const row of resultsFor(batch, 'direct_edge_props')) {\n    const src = typeof row['src'] === 'string' ? row['src'] : ''\n    const dst = typeof row['dst'] === 'string' ? row['dst'] : ''\n    if (!src || !dst) continue\n    edgeProps.set(edgeKey(src, dst), row)\n  }\n\n  for (const flow of flows) {\n    const props = edgeProps.get(edgeKey(flow.src, flow.dst))\n    if (!props) continue\n    flow.amount_usd_sum = numberValue(props['amount_usd_sum']) ?? flow.amount_usd_sum\n    flow.tx_count = numberValue(props['tx_count'])\n    flow.first_tx_id = typeof props['first_tx_id'] === 'string' ? props['first_tx_id'] : undefined\n    flow.last_tx_id = typeof props['last_tx_id'] === 'string' ? props['last_tx_id'] : undefined\n    flow.first_seen_timestamp = numberValue(props['first_seen_timestamp']) ?? flow.first_seen_timestamp\n    flow.last_seen_timestamp = numberValue(props['last_seen_timestamp']) ?? flow.last_seen_timestamp\n  }\n\n  for (const deposit of deposits) {\n    const props = edgeProps.get(edgeKey(deposit.address, deposit.exchangeAddress))\n    if (!props) continue\n    deposit.amount_usd_sum = numberValue(props['amount_usd_sum'])\n  }\n}\n\nasync function collectProbeTrace(\n  remoteClient: Client,\n  options: Required<Pick<TraceFundsOptions, 'seedAddress' | 'network' | 'maxHops' | 'perAddressLimit' | 'minAmountSum'>> & Pick<TraceFundsOptions, 'includeDepositTraceback' | 'activityWindow' | 'topologyScope'>,\n): Promise<{ flows: TraceFlow[]; deposits: TraceDeposit[]; sourceMatches: SourceMatch[]; reverseLeads: ReverseLead[]; tracebackWarnings: string[] }> {\n  const topologyScope = options.topologyScope ?? DEFAULT_TOPOLOGY_SCOPE\n  const forwardBatch = await callGraphBatch(remoteClient, options.network, [\n    ...forwardExchangeQueries(options.seedAddress, Math.max(options.perAddressLimit * 20, 200), options.minAmountSum, options.maxHops, topologyScope, options.activityWindow),\n  ], topologyScope)\n  const forwardRows = rowsMatchingMinimumAmount((forwardBatch.facts?.queries ?? [])\n    .filter((query) => query.id?.startsWith('forward_exchange_paths_'))\n    .flatMap((query) => {\n      if (query.ok === false) throw new Error(query.error || `Query failed: ${query.id}`)\n      return query.results ?? []\n    }), options.minAmountSum)\n  const { flows, deposits } = flowsFromForwardRows(forwardRows)\n  await hydrateDirectEdgeProps(remoteClient, options.network, flows, deposits, topologyScope)\n  const uniqueDepositAddresses = [...new Set(deposits.map((deposit) => deposit.address))]\n\n  const sourceMatches: SourceMatch[] = []\n  const tracebackWarnings: string[] = []\n  if (options.includeDepositTraceback !== false && uniqueDepositAddresses.length > 0) {\n    let backwardQueries: NonNullable<NonNullable<ParsedGraphBatch['facts']>['queries']> = []\n    try {\n      const backwardBatch = await callGraphBatch(\n        remoteClient,\n        options.network,\n        uniqueDepositAddresses.slice(0, Math.max(1, Math.floor(20 / options.maxHops))).flatMap((address, index) => backwardSourceQueries(`backward_from_deposit_${index + 1}`, address, options.maxHops, topologyScope)),\n        topologyScope,\n      )\n      backwardQueries = backwardBatch.facts?.queries ?? []\n    } catch (err) {\n      tracebackWarnings.push(`deposit traceback batch failed: ${(err as Error).message}`)\n    }\n    for (const query of backwardQueries) {\n      if (query.ok === false) {\n        tracebackWarnings.push(`deposit traceback query ${query.id} failed: ${query.error || 'unknown error'}`)\n        continue\n      }\n      for (const row of query.results ?? []) {\n        const pathAddresses = stringArrayValue(row['addresses']) ?? []\n        const pathNodes = Array.isArray(row['path_nodes'])\n          ? row['path_nodes'].map((node, index) => nodeMetadataFromValue(node, pathAddresses[index])).filter((node): node is GraphNodeMetadata => Boolean(node))\n          : undefined\n        const depositAddress = typeof row['deposit_address'] === 'string' ? row['deposit_address'] : pathAddresses[0]\n        const sourceExchange = typeof row['source_exchange'] === 'string' ? row['source_exchange'] : pathAddresses[pathAddresses.length - 1]\n        if (!depositAddress || !sourceExchange) continue\n        const sourceNode = {\n          address: sourceExchange,\n          labels: stringArrayValue(row['source_display_labels']),\n          system_labels: stringArrayValue(row['source_system_labels']) ?? stringArrayValue(row['source_labels']),\n        }\n        sourceMatches.push({\n          deposit_address: depositAddress,\n          source_exchange: sourceExchange,\n          source_labels: stringArrayValue(row['source_labels']),\n          sourceNode,\n          hops: numberValue(row['hops']) ?? Math.max(pathAddresses.length - 1, 0),\n          path: pathAddresses,\n          pathNodes,\n        })\n      }\n    }\n  }\n\n  const reverseLeads: ReverseLead[] = []\n  if (options.includeDepositTraceback !== false && uniqueDepositAddresses.length > 0) {\n    let reverseRows: Array<Record<string, unknown>> = []\n    try {\n      const reverseBatch = await callGraphBatch(remoteClient, options.network, [reverseLeadsQuery(uniqueDepositAddresses, topologyScope)], topologyScope)\n      try {\n        reverseRows = resultsFor(reverseBatch, 'reverse_1hop')\n      } catch (err) {\n        tracebackWarnings.push(`deposit traceback query reverse_1hop failed: ${(err as Error).message}`)\n      }\n    } catch (err) {\n      tracebackWarnings.push(`deposit traceback batch failed: ${(err as Error).message}`)\n    }\n    for (const row of reverseRows) {\n      const address = typeof row['address'] === 'string' ? row['address'] : ''\n      const depositAddress = typeof row['deposit_address'] === 'string' ? row['deposit_address'] : ''\n      if (!address || !depositAddress) continue\n      const labels = stringArrayValue(row['display_labels']) ?? stringArrayValue(row['labels']) ?? []\n      const amountUsd = numberValue(row['amount_usd']) ?? 0\n      const reason = labels.length > 0 ? 'labeled_entity' : amountUsd > 100000 ? 'high_volume_sender' : ''\n      if (!reason) continue\n      reverseLeads.push({\n        address,\n        labels,\n        node: {\n          address,\n          labels,\n          system_labels: stringArrayValue(row['system_labels']),\n          addresses: stringArrayValue(row['member_addresses']),\n          risk_score: numberValue(row['risk_score']),\n          risk_level: typeof row['risk_level'] === 'string' && row['risk_level'].trim() ? row['risk_level'] : undefined,\n        },\n        deposit_address: depositAddress,\n        amount_usd: numberValue(row['amount_usd']),\n        reason,\n      })\n    }\n  }\n\n  return { flows, deposits, sourceMatches, reverseLeads, tracebackWarnings }\n}\n\nfunction buildAliases(seedAddress: string, deposits: TraceDeposit[], sourceMatches: SourceMatch[], reverseLeads: ReverseLead[]): AliasTracker {\n  const aliases = new AliasTracker()\n  aliases.assign(seedAddress, 'V')\n  for (const deposit of deposits) {\n    for (const address of deposit.path.slice(1, -2)) aliases.assign(address, 'I')\n    aliases.assign(deposit.address, 'D')\n    aliases.assign(deposit.exchangeAddress, 'E')\n  }\n  for (const source of sourceMatches) {\n    aliases.assign(source.source_exchange, 'X')\n    for (const address of source.path.slice(1, -1)) aliases.assign(address, 'I')\n  }\n  for (const lead of reverseLeads) aliases.assign(lead.address, 'L')\n  return aliases\n}\n\nfunction buildGraph(seedAddress: string, network: string, flows: TraceFlow[], deposits: TraceDeposit[], sourceMatches: SourceMatch[], reverseLeads: ReverseLead[]): Record<string, unknown> {\n  type NodeAccumulator = {\n    in: number\n    out: number\n    labels: string[]\n    systemLabels: string[]\n    memberAddresses?: string[]\n    riskScore?: number\n    riskLevel?: string\n    roles: Set<string>\n  }\n\n  const totals = new Map<string, NodeAccumulator>()\n  const ensure = (address: string) => {\n    if (!totals.has(address)) {\n      totals.set(address, {\n        in: 0,\n        out: 0,\n        labels: [],\n        systemLabels: [],\n        roles: new Set(address === seedAddress ? ['seed'] : []),\n      })\n    }\n    return totals.get(address)!\n  }\n  const mergeNode = (address: string, metadata?: GraphNodeMetadata, role?: string, systemLabelsFallback?: string[]) => {\n    const node = ensure(address)\n    node.labels = uniqueStrings([...node.labels, ...(metadata?.labels ?? [])])\n    node.systemLabels = uniqueStrings([...node.systemLabels, ...(metadata?.system_labels ?? []), ...(systemLabelsFallback ?? [])])\n    if (metadata?.addresses?.length) node.memberAddresses = uniqueStrings([...(node.memberAddresses ?? []), ...metadata.addresses])\n    if (metadata?.risk_score !== undefined) node.riskScore = metadata.risk_score\n    if (metadata?.risk_level) node.riskLevel = normalizeRiskLevel(metadata.risk_level) ?? node.riskLevel\n    if (role) node.roles.add(role)\n    return node\n  }\n\n  for (const flow of flows) {\n    const src = mergeNode(flow.src, flow.src_node, undefined, flow.src_labels)\n    src.out += flow.amount_usd_sum\n    const dst = mergeNode(flow.dst, flow.dst_node, undefined, flow.dst_labels)\n    dst.in += flow.amount_usd_sum\n    if (isExchangeFlow(flow)) dst.roles.add('exchange')\n  }\n  for (const deposit of deposits) {\n    for (const node of deposit.pathNodes ?? []) mergeNode(node.address, node)\n    mergeNode(deposit.address, deposit.pathNodes?.find((node) => node.address === deposit.address), 'deposit_candidate')\n    mergeNode(deposit.exchangeAddress, deposit.exchangeNode, 'exchange', deposit.exchangeLabels)\n  }\n  for (const source of sourceMatches) {\n    for (const node of source.pathNodes ?? []) mergeNode(node.address, node)\n    mergeNode(source.source_exchange, source.sourceNode, 'exchange', source.source_labels)\n  }\n  for (const lead of reverseLeads) {\n    mergeNode(lead.address, lead.node ?? { address: lead.address, labels: lead.labels }, 'lead')\n    const deposit = ensure(lead.deposit_address)\n    deposit.in += lead.amount_usd ?? 0\n  }\n  const sourceMatchEdges = sourceMatches.flatMap((source) => {\n    const path = source.path.length >= 2 ? source.path : [source.deposit_address, source.source_exchange]\n    const edges: Array<Record<string, unknown>> = []\n    for (let index = path.length - 1; index > 0; index -= 1) {\n      edges.push({\n        source: path[index],\n        target: path[index - 1],\n        edge_type: 'flows_to',\n        usd_amount: 0,\n        amount_usd_sum: 0,\n        tx_count: 0,\n        direction: 'traceback',\n      })\n    }\n    return edges\n  })\n\n  return normalizeGraphPayload({\n    schema: 'chain-insights.graph.v1',\n    nodes: [...totals.entries()].map(([address, data]) => ({\n      id: address,\n      address,\n      node_type: 'address',\n      labels: uniqueStrings(data.labels),\n      ...(data.systemLabels.length > 0 ? { system_labels: uniqueStrings(data.systemLabels) } : {}),\n      ...(data.memberAddresses?.length ? { member_addresses: data.memberAddresses } : {}),\n      ...(data.riskScore !== undefined ? { risk_score: data.riskScore } : {}),\n      ...(data.riskLevel ? { risk_level: data.riskLevel } : {}),\n      ...(data.roles.size > 0 ? { roles: [...data.roles] } : {}),\n      flow_in_usd: data.in,\n      flow_out_usd: data.out,\n    })),\n    edges: [\n      ...flows.map((flow) => ({\n        source: flow.src,\n        target: flow.dst,\n        edge_type: 'flows_to',\n        usd_amount: flow.amount_usd_sum,\n        amount_usd_sum: flow.amount_usd_sum,\n        tx_count: flow.tx_count ?? 0,\n        first_seen_timestamp: flow.first_seen_timestamp,\n        last_seen_timestamp: flow.last_seen_timestamp,\n        first_tx_id: flow.first_tx_id,\n        last_tx_id: flow.last_tx_id,\n        terminal_exchange: flow.terminal_exchange,\n      })),\n      ...sourceMatchEdges,\n      ...reverseLeads.map((lead) => ({\n        source: lead.address,\n        target: lead.deposit_address,\n        edge_type: 'flows_to',\n        usd_amount: lead.amount_usd ?? 0,\n        amount_usd_sum: lead.amount_usd ?? 0,\n        tx_count: 0,\n        direction: 'reverse_1hop_lead',\n      })),\n    ],\n    flows,\n    deposits,\n    source_matches: sourceMatches,\n    reverse_leads: reverseLeads,\n    edge_anchors: [],\n    metadata: {\n      seed_address: seedAddress,\n      network,\n      generated_at: new Date().toISOString(),\n    },\n  })\n}\n\nfunction buildMarkdownReport(seedAddress: string, network: string, flows: TraceFlow[], deposits: TraceDeposit[], sourceMatches: SourceMatch[], reverseLeads: ReverseLead[], aliases: AliasTracker, graphPath: string, schemaPath: string): string {\n  const lines = [\n    `# Trace Funds: ${seedAddress}`,\n    '',\n    `Network: \\`${network}\\``,\n    `Schema: \\`${schemaPath}\\``,\n    `Graph: \\`${graphPath}\\``,\n    '',\n    '## Probe Summary',\n    '',\n    `- Exchange endpoint(s): ${[...new Set(deposits.map((deposit) => aliases.alias(deposit.exchangeAddress) ?? deposit.exchangeAddress))].join(', ') || 'none'}`,\n    `- Deposit candidate(s): ${[...new Set(deposits.map((deposit) => aliases.alias(deposit.address) ?? deposit.address))].join(', ') || 'none'}`,\n    `- Traceback source exchange path(s): ${sourceMatches.length}`,\n    `- Reverse 1-hop lead(s): ${reverseLeads.length}`,\n    '',\n    '## Flow Table',\n    '',\n    '| Hop | Source | Destination | amount_usd_sum | tx_count | first_seen_timestamp | last_seen_timestamp | first_tx_id | terminal_exchange |',\n    '|---:|---|---|---:|---:|---:|---:|---|---|',\n    ...flows.map((flow) => [\n      `| ${flow.hop}`,\n      `\\`${flow.src}\\``,\n      `\\`${flow.dst}\\``,\n      flow.amount_usd_sum,\n      flow.tx_count ?? '',\n      flow.first_seen_timestamp ?? '',\n      flow.last_seen_timestamp ?? '',\n      flow.first_tx_id ? `\\`${flow.first_tx_id}\\`` : '',\n      flow.terminal_exchange ? 'yes' : 'no',\n    ].join(' | ') + ' |'),\n    '',\n    '## Mermaid',\n    '',\n    '```mermaid',\n    'flowchart LR',\n    ...flows.map((flow, index) =>\n      `  n${index}[\"${flow.src}\"] -->|\"amount_usd_sum ${flow.amount_usd_sum}${flow.terminal_exchange ? '; exchange endpoint' : ''}\"| m${index}[\"${flow.dst}\"]`\n    ),\n    '```',\n  ]\n  return lines.join('\\n') + '\\n'\n}\n\nfunction probeEvidence(seedAddress: string, network: string, schemaPath: string, aliases: AliasTracker, flows: TraceFlow[], deposits: TraceDeposit[], sourceMatches: SourceMatch[], reverseLeads: ReverseLead[], evidenceSource = 'track_funds'): Record<string, unknown> {\n  return {\n    schema: 'chain-insights.probe_evidence.v1',\n    source: evidenceSource,\n    network,\n    seed_address: seedAddress,\n    schema_ref: schemaPath,\n    address_map: aliases.addressMap(),\n    fund_flows: [\n      ...deposits.map((deposit, index) => ({\n        id: `F${index + 1}`,\n        type: 'deposit',\n        path: deposit.path.map((address) => aliases.alias(address) ?? address),\n        deposit: aliases.alias(deposit.address),\n        exchange: aliases.alias(deposit.exchangeAddress),\n        amount_usd_sum: deposit.amount_usd_sum,\n        hops: deposit.hops,\n      })),\n      ...sourceMatches.map((source, index) => ({\n        id: `S${index + 1}`,\n        type: 'source',\n        path: [...source.path].reverse().map((address) => aliases.alias(address) ?? address),\n        source_exchange: aliases.alias(source.source_exchange),\n        deposit: aliases.alias(source.deposit_address),\n        hops: source.hops,\n      })),\n    ],\n    reverse_leads: reverseLeads.map((lead) => ({\n      alias: aliases.alias(lead.address),\n      address: lead.address,\n      reason: lead.reason,\n      labels: lead.labels,\n      deposit: aliases.alias(lead.deposit_address),\n      amount_usd: lead.amount_usd,\n    })),\n    outgoing_flows: flows.map((flow) => ({\n      hop: flow.hop,\n      src: aliases.alias(flow.src) ?? flow.src,\n      dst: aliases.alias(flow.dst) ?? flow.dst,\n      amount_usd_sum: flow.amount_usd_sum,\n      tx_count: flow.tx_count,\n      first_seen_timestamp: flow.first_seen_timestamp,\n      last_seen_timestamp: flow.last_seen_timestamp,\n      first_tx_id: flow.first_tx_id,\n      last_tx_id: flow.last_tx_id,\n      terminal_exchange: flow.terminal_exchange,\n    })),\n  }\n}\n\nfunction tableCsv(flows: TraceFlow[]): string {\n  const rows = ['hop,src,dst,amount_usd_sum,tx_count,first_seen_timestamp,last_seen_timestamp,first_tx_id,last_tx_id,terminal_exchange']\n  for (const flow of flows) {\n    rows.push([\n      flow.hop,\n      flow.src,\n      flow.dst,\n      flow.amount_usd_sum,\n      flow.tx_count ?? '',\n      flow.first_seen_timestamp ?? '',\n      flow.last_seen_timestamp ?? '',\n      flow.first_tx_id ?? '',\n      flow.last_tx_id ?? '',\n      flow.terminal_exchange ? 'true' : 'false',\n    ].map((value) => JSON.stringify(String(value))).join(','))\n  }\n  return rows.join('\\n') + '\\n'\n}\n\nfunction htmlEscape(value: unknown): string {\n  return String(value ?? '')\n    .replaceAll('&', '&amp;')\n    .replaceAll('<', '&lt;')\n    .replaceAll('>', '&gt;')\n    .replaceAll('\"', '&quot;')\n    .replaceAll(\"'\", '&#39;')\n}\n\nfunction buildTableHtml(seedAddress: string, network: string, flows: TraceFlow[], deposits: TraceDeposit[], sourceMatches: SourceMatch[], reverseLeads: ReverseLead[]): string {\n  const headers = [\n    'hop',\n    'src',\n    'dst',\n    'amount_usd_sum',\n    'tx_count',\n    'first_seen_timestamp',\n    'last_seen_timestamp',\n    'first_tx_id',\n    'last_tx_id',\n    'terminal_exchange_display',\n  ] as const\n  const headerLabels: Record<typeof headers[number], string> = {\n    hop: 'Hop',\n    src: 'Source',\n    dst: 'Destination',\n    amount_usd_sum: 'amount_usd_sum',\n    tx_count: 'tx_count',\n    first_seen_timestamp: 'first_seen_timestamp',\n    last_seen_timestamp: 'last_seen_timestamp',\n    first_tx_id: 'first_tx_id',\n    last_tx_id: 'last_tx_id',\n    terminal_exchange_display: 'terminal_exchange',\n  }\n  const rows = flows.map((flow) => {\n    const values: Record<string, unknown> = {\n      ...flow,\n      terminal_exchange_display: flow.terminal_exchange ? 'yes' : 'no',\n    }\n    return `<tr>${headers.map((header) => `<td>${htmlEscape(values[header])}</td>`).join('')}</tr>`\n  }).join('\\n')\n\n  return `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Trace Funds Table - ${htmlEscape(seedAddress)}</title>\n<style>\n  :root { color-scheme: dark; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; background: #0b0d12; color: #f4f2ea; }\n  body { margin: 0; background: #0b0d12; color: #f4f2ea; }\n  main { padding: 24px; }\n  h1 { font-size: 20px; margin: 0 0 8px; font-weight: 650; }\n  .meta { display: grid; gap: 6px; margin: 0 0 20px; color: rgba(244,242,234,.72); font-size: 13px; }\n  .summary { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 20px; }\n  .pill { border: 1px solid rgba(242,221,166,.25); background: rgba(242,221,166,.08); border-radius: 999px; padding: 6px 10px; font-size: 12px; color: #f2dda6; }\n  .table-wrap { overflow: auto; border: 1px solid rgba(255,255,255,.1); border-radius: 8px; background: #10131b; }\n  table { border-collapse: collapse; width: 100%; min-width: 1180px; font-size: 12px; }\n  th, td { border-bottom: 1px solid rgba(255,255,255,.08); padding: 8px 10px; text-align: left; vertical-align: top; }\n  th { position: sticky; top: 0; background: #161a24; color: #f2dda6; font-weight: 600; z-index: 1; }\n  td { color: rgba(244,242,234,.86); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }\n  tr:hover td { background: rgba(242,221,166,.045); }\n</style>\n</head>\n<body>\n<main>\n  <h1>Trace Funds Table</h1>\n  <div class=\"meta\">\n    <div>Network: <strong>${htmlEscape(network)}</strong></div>\n    <div>Seed: <strong>${htmlEscape(seedAddress)}</strong></div>\n    <div>Generated: <strong>${htmlEscape(new Date().toISOString())}</strong></div>\n  </div>\n  <div class=\"summary\">\n    <span class=\"pill\">${flows.length} FLOWS_TO edges</span>\n    <span class=\"pill\">${deposits.length} deposit candidates</span>\n    <span class=\"pill\">${sourceMatches.length} traceback source paths</span>\n    <span class=\"pill\">${reverseLeads.length} reverse 1-hop leads</span>\n  </div>\n  <div class=\"table-wrap\">\n    <table>\n      <thead><tr>${headers.map((header) => `<th>${htmlEscape(headerLabels[header])}</th>`).join('')}</tr></thead>\n      <tbody>\n${rows}\n      </tbody>\n    </table>\n  </div>\n</main>\n</body>\n</html>\n`\n}\n\nfunction summarize(seedAddress: string, network: string, flows: TraceFlow[], sourceMatches: SourceMatch[], reverseLeads: ReverseLead[], aliases: AliasTracker, files: TraceFundsResult['files'], continuation: TraceFundsResult['continuation']): string {\n  const totalAmount = flows.reduce((sum, flow) => sum + flow.amount_usd_sum, 0)\n  const byHop = new Map<number, number>()\n  for (const flow of flows) byHop.set(flow.hop, (byHop.get(flow.hop) ?? 0) + 1)\n  const depositCount = continuation.depositAddresses.length\n  const exchangeCount = continuation.exchangeAddresses.length\n  const hasFiles = Object.values(files).some((value) => value.length > 0)\n  return [\n    `Trace complete for ${network}:${seedAddress}`,\n    '',\n    `Facts: ${flows.length} FLOWS_TO edge(s), sum of traced edge amount_usd_sum values ${Number(totalAmount.toFixed(8))}.`,\n    `By hop: ${[...byHop.entries()].map(([hop, count]) => `hop ${hop}: ${count}`).join(', ') || 'none'}.`,\n    `Exchange endpoints reached: ${exchangeCount}. Deposit candidate address(es): ${depositCount}.`,\n    `Traceback source path(s): ${sourceMatches.length}. Reverse 1-hop lead(s): ${reverseLeads.length}.`,\n    '',\n    hasFiles\n      ? [\n          'Files written:',\n          `- schema: ${files.schema}`,\n          `- compact evidence JSON: ${files.compactEvidence}`,\n          `- graph JSON: ${files.graph}`,\n          `- graph HTML: ${files.graphHtml}`,\n          `- table CSV: ${files.table}`,\n          `- table HTML: ${files.tableHtml}`,\n          `- report: ${files.report}`,\n        ].join('\\n')\n      : 'Files written: disabled by stateless proxy mode.',\n    '',\n    `Continuation hint: ${continuation.hint}`,\n    continuation.depositAddresses.length > 0\n      ? `Deposit candidates: ${continuation.depositAddresses.map((address) => aliases.alias(address) ?? address).join(', ')}`\n      : 'Deposit candidates: none reached in this bounded trace.',\n    continuation.nextHopAddresses.length > 0\n      ? `Next addresses: ${continuation.nextHopAddresses.join(', ')}`\n      : 'Next addresses: none found in this trace.',\n  ].join('\\n')\n}\n\nexport async function runFundFlowProbe(\n  remoteClient: Client,\n  _config: Pick<InvestigatorConfig, 'dataDir' | 'serverPort'>,\n  options: TraceFundsOptions,\n): Promise<TraceFundsResult> {\n  const seedAddress = options.seedAddress.trim()\n  const network = options.network.trim()\n  if (!seedAddress) throw new Error('seed_address is required')\n  if (!network) throw new Error('network is required')\n  if (options.activityWindow && (!Number.isFinite(options.activityWindow.fromMs) || (options.activityWindow.toMs !== undefined && !Number.isFinite(options.activityWindow.toMs)))) {\n    throw new Error('activity window timestamps must be finite numbers')\n  }\n\n  const maxHops = clampInt(options.maxHops, 3, 1, 5)\n  const perAddressLimit = clampInt(options.perAddressLimit, 5, 1, 10)\n  const minAmountSum = Math.max(0, options.minAmountSum ?? 0)\n  const evidenceSource = options.evidenceSource ?? 'track_funds'\n  const writeArtifacts = options.writeArtifacts !== false\n\n  const paths = writeArtifacts ? workspaceOutputPaths() : undefined\n  if (paths) await ensureDirs(paths)\n\n  const schemaResult = paths\n    ? await loadOrCaptureTopologySchema(remoteClient, paths, network)\n    : {\n        schema: {\n          schema: 'chain-insights.runtime_graph_schema.v1',\n          network,\n          source: 'stateless_proxy_mode',\n        },\n        filePath: 'stateless://runtime-schema-not-written',\n      }\n  const { flows, deposits, sourceMatches, reverseLeads, tracebackWarnings } = await collectProbeTrace(remoteClient, { seedAddress, network, maxHops, perAddressLimit, minAmountSum, activityWindow: options.activityWindow, includeDepositTraceback: options.includeDepositTraceback, topologyScope: options.topologyScope })\n  const aliases = buildAliases(seedAddress, deposits, sourceMatches, reverseLeads)\n  const slug = `${new Date().toISOString().replace(/[-:]/g, '').replace(/\\.\\d{3}Z$/, 'Z')}_${sanitizeSegment(seedAddress.slice(0, 16))}`\n  const compact = probeEvidence(seedAddress, network, schemaResult.filePath, aliases, flows, deposits, sourceMatches, reverseLeads, evidenceSource)\n  const graph = buildGraph(seedAddress, network, flows, deposits, sourceMatches, reverseLeads)\n\n  const compactPath = paths ? path.join(paths.reportTablesRoot, `${slug}.compact-evidence.json`) : ''\n  const graphPath = paths ? path.join(paths.reportGraphsRoot, `${slug}.graph.json`) : ''\n  const graphHtmlPath = paths ? path.join(paths.reportsRoot, `${slug}.graph.html`) : ''\n  const tablePath = paths ? path.join(paths.reportTablesRoot, `${slug}.flows.csv`) : ''\n  const tableHtmlPath = paths ? path.join(paths.reportsRoot, `${slug}.table.html`) : ''\n  const reportPath = paths ? path.join(paths.reportsRoot, `${slug}.trace-report.md`) : ''\n\n  if (paths) {\n    const { generateInlineGraphHtml } = await import('../viz/html-generator.js')\n    await writeFile(compactPath, JSON.stringify(compact, null, 2) + '\\n', { mode: 0o600 })\n    await writeFile(graphPath, JSON.stringify(graph, null, 2) + '\\n', { mode: 0o600 })\n    await writeFile(graphHtmlPath, generateInlineGraphHtml(graph), { mode: 0o600 })\n    await writeFile(tablePath, tableCsv(flows), { mode: 0o600 })\n    await writeFile(tableHtmlPath, buildTableHtml(seedAddress, network, flows, deposits, sourceMatches, reverseLeads), { mode: 0o600 })\n    await writeFile(reportPath, buildMarkdownReport(seedAddress, network, flows, deposits, sourceMatches, reverseLeads, aliases, graphPath, schemaResult.filePath), { mode: 0o600 })\n  }\n  const depositAddresses = [...new Set(deposits.map((deposit) => deposit.address))]\n  const exchangeAddresses = [...new Set(deposits.map((deposit) => deposit.exchangeAddress))]\n  const leaves: string[] = []\n  const continuation = {\n    nextHopAddresses: leaves.slice(0, 20),\n    depositAddresses,\n    exchangeAddresses,\n    hint: depositAddresses.length > 0\n      ? `Found ${depositAddresses.length} deposit candidate(s), defined as the address one hop before an exchange endpoint. Do not continue through exchange nodes.`\n      : leaves.length > 0\n        ? `No exchange endpoint reached yet. Continue from ${leaves.length} non-exchange leaf destination(s) with the same tool, or raise the result budget if the current trace stopped early.`\n        : 'No exchange endpoint or non-exchange leaf destinations found; inspect graph/report files or lower min_amount_sum.',\n  }\n  const files = {\n    schema: schemaResult.filePath,\n    compactEvidence: compactPath,\n    graph: graphPath,\n    graphHtml: graphHtmlPath,\n    table: tablePath,\n    tableHtml: tableHtmlPath,\n    report: reportPath,\n  }\n\n  return {\n    summaryText: summarize(seedAddress, network, flows, sourceMatches, reverseLeads, aliases, files, continuation),\n    compactEvidence: compact,\n    graphData: graph,\n    files,\n    continuation,\n    addressMap: aliases.compactAddressMap(),\n    tracebackWarnings,\n  }\n}\n","import { createHash } from 'node:crypto'\nimport { mkdir, writeFile } from 'node:fs/promises'\nimport path from 'node:path'\nimport type { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport type { ContentBlock } from '@modelcontextprotocol/sdk/types.js'\nimport type { InvestigatorConfig } from '../config/schema.js'\nimport { activityWindowPredicates, runFundFlowProbe, type TraceActivityWindow, type TraceFundsResult, type TopologyScope, DEFAULT_TOPOLOGY_SCOPE } from './trace-funds.js'\nimport { normalizeGraphPayload } from '../viz/graph-normalizer.js'\nimport { isUnscoredRiskLevel, normalizeRiskLevel, riskSeverityRank } from './risk-level.js'\nimport { workspaceOutputPaths } from '../workspace/output-root.js'\n\ntype RemoteToolResult = {\n  content?: ContentBlock[]\n  isError?: boolean\n}\n\ninterface ParsedGraphBatch {\n  facts?: {\n    queries?: Array<{\n      id?: string\n      ok?: boolean\n      results?: Array<Record<string, unknown>>\n      error?: string\n    }>\n  }\n}\n\ntype QueryFailure = {\n  id: string\n  error: string\n}\n\nconst GRAPH_QUERY_BATCH_TIMEOUT_SECONDS = 10\nconst GRAPH_QUERY_BATCH_REQUEST_TIMEOUT_MS = 5 * 60 * 1000\n// The AC12 archive-retry hint is a best-effort nicety, not part of the trace\n// itself: bound it tightly so a hung/slow capabilities call can never stall\n// (let alone fail) the actual trace/risk result.\nconst ARCHIVE_HINT_CAPABILITY_TIMEOUT_MS = 5000\n\nexport interface AddressRiskOptions {\n  address: string\n  network: string\n  compareAddress?: string\n  writeArtifacts?: boolean\n  topologyScope?: TopologyScope\n}\n\nexport interface TrackFundsOptions {\n  trustedAddresses: string | string[]\n  untrustedAddresses?: string | string[]\n  network: string\n  maxHops?: number\n  perAddressLimit?: number\n  minAmountSum?: number\n  topologyScope?: TopologyScope\n}\n\nfunction escapeCypherString(value: string): string {\n  return value.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"')\n}\n\nfunction textFromToolResult(result: RemoteToolResult): string {\n  return (result.content ?? [])\n    .filter((item): item is Extract<ContentBlock, { type: 'text' }> => item.type === 'text')\n    .map((item) => item.text)\n    .join('\\n')\n}\n\nfunction parseGraphBatchResult(result: RemoteToolResult): ParsedGraphBatch {\n  const text = textFromToolResult(result).trim()\n  if (!text) throw new Error('graph_query_batch returned no text content')\n  const parsed = JSON.parse(text) as ParsedGraphBatch\n  if (!parsed.facts?.queries) throw new Error('graph_query_batch response did not include facts.queries')\n  return parsed\n}\n\nfunction topologyGraphQuery(query: string, scope: TopologyScope = DEFAULT_TOPOLOGY_SCOPE): string {\n  const trimmed = query.trim()\n  if (/^USE\\s+/i.test(trimmed)) return trimmed\n  return `USE ${scope} ${trimmed}`\n}\n\nfunction collectQueryFailure(failures: QueryFailure[], id: string, error: string | undefined): void {\n  failures.push({ id, error: error || 'unknown error' })\n}\n\nfunction optionalResultsFor(batch: ParsedGraphBatch, id: string, failures: QueryFailure[]): Array<Record<string, unknown>> {\n  const query = batch.facts?.queries?.find((entry) => entry.id === id)\n  if (!query) return []\n  if (query.ok === false) {\n    collectQueryFailure(failures, id, query.error)\n    return []\n  }\n  return query.results ?? []\n}\n\nfunction optionalResultsWithPrefix(batch: ParsedGraphBatch, prefix: string, failures: QueryFailure[]): Array<Record<string, unknown>> {\n  return (batch.facts?.queries ?? [])\n    .filter((entry) => entry.id?.startsWith(prefix))\n    .flatMap((entry) => {\n      if (entry.ok === false) {\n        collectQueryFailure(failures, entry.id ?? prefix, entry.error)\n        return []\n      }\n      return entry.results ?? []\n    })\n}\n\nasync function callGraphBatch(\n  remoteClient: Client,\n  network: string,\n  queries: Array<{ id: string; query: string }>,\n  topologyScope: TopologyScope = DEFAULT_TOPOLOGY_SCOPE,\n): Promise<ParsedGraphBatch> {\n  const result = await remoteClient.callTool(\n    {\n      name: 'graph_query_batch',\n      arguments: {\n        network,\n        queries: queries.map((query) => ({\n          ...query,\n          query: topologyGraphQuery(query.query, topologyScope),\n        })),\n        per_query_timeout_seconds: GRAPH_QUERY_BATCH_TIMEOUT_SECONDS,\n      },\n    },\n    undefined,\n    {\n      timeout: GRAPH_QUERY_BATCH_REQUEST_TIMEOUT_MS,\n      maxTotalTimeout: GRAPH_QUERY_BATCH_REQUEST_TIMEOUT_MS,\n    },\n  ) as RemoteToolResult\n  if (result.isError) throw new Error(textFromToolResult(result) || 'graph_query_batch failed')\n  return parseGraphBatchResult(result)\n}\n\n// Best-effort archive_topology availability check for the AC12 observability\n// hint (retry with archive when a live_topology call finds nothing). Never\n// throws: a failed/unsupported capabilities call just means no hint is shown.\nasync function archiveTopologyAvailable(remoteClient: Client, network: string): Promise<boolean> {\n  try {\n    const result = await remoteClient.callTool(\n      { name: 'network_capabilities', arguments: {} },\n      undefined,\n      { timeout: ARCHIVE_HINT_CAPABILITY_TIMEOUT_MS, maxTotalTimeout: ARCHIVE_HINT_CAPABILITY_TIMEOUT_MS },\n    ) as RemoteToolResult\n    if (result.isError) return false\n    const text = textFromToolResult(result).trim()\n    if (!text) return false\n    const parsed = JSON.parse(text) as {\n      networks?: Array<{ network?: string; layers?: { topology?: { archive?: { enabled?: boolean } } } }>\n      facts?: { capabilities?: { networks?: Array<{ network?: string; layers?: { topology?: { archive?: { enabled?: boolean } } } }> } }\n    }\n    const networks = parsed.facts?.capabilities?.networks ?? parsed.networks\n    const entry = networks?.find((candidate) => candidate.network === network)\n    return entry?.layers?.topology?.archive?.enabled === true\n  } catch {\n    return false\n  }\n}\n\n// Appends the AC12 archive-retry hint to a trace/risk warnings array when the\n// call ran on live_topology, found nothing, and archive_topology is available.\nasync function archiveRetryHint(\n  remoteClient: Client,\n  network: string,\n  topologyScope: TopologyScope,\n  foundNothing: boolean,\n): Promise<string[]> {\n  if (topologyScope !== 'live_topology' || !foundNothing) return []\n  const archiveAvailable = await archiveTopologyAvailable(remoteClient, network)\n  return archiveAvailable\n    ? ['No results on live_topology; archive_topology is available for this network and covers full history -- retry with topology_scope=archive_topology.']\n    : []\n}\n\nfunction parseAddressList(value: string | string[] | undefined): string[] {\n  const raw = Array.isArray(value) ? value.join(',') : value ?? ''\n  return raw\n    .split(',')\n    .map((entry) => entry.trim())\n    .filter(Boolean)\n}\n\nconst CANONICAL_HEX_FORM_PATTERN = /^0x[0-9a-fA-F]+$/\n\nfunction memberFormOf(input: string, network: string): string {\n  const prefix = `${network}:`\n  return input.startsWith(prefix) ? input.slice(prefix.length) : input\n}\n\nfunction canonicalIdentityKeyFor(network: string, memberForm: string): string | undefined {\n  if (!CANONICAL_HEX_FORM_PATTERN.test(memberForm)) return undefined\n  return `${network}:${memberForm.toLowerCase()}`\n}\n\nfunction memberAddressResolutionQuery(id: string, memberForm: string): { id: string; query: string } {\n  return {\n    id,\n    query: [\n      `MATCH (m:Address {address: \"${escapeCypherString(memberForm)}\"})<-[:HAS_ADDRESS]-(i:Identity)`,\n      'RETURN i.identity_id AS identity_id',\n      'LIMIT 1',\n    ].join(' '),\n  }\n}\n\n// canonicalIdentityKeyFor() recognizes the CANONICAL FORM (0x...) but does not\n// verify the identity actually exists in the graph. A made-up 0x address would\n// otherwise be treated as \"resolved\" and traced, in violation of R2/R3.\n// This confirms existence for candidates that already look canonical.\nfunction identityExistenceQuery(id: string, identityId: string): { id: string; query: string } {\n  return {\n    id,\n    query: [\n      `MATCH (i:Identity {identity_id: \"${escapeCypherString(identityId)}\"})`,\n      'RETURN i.identity_id AS identity_id',\n      'LIMIT 1',\n    ].join(' '),\n  }\n}\n\nfunction identityMemberAddressesQuery(identityKeys: string[]): { id: string; query: string } {\n  const predicates = identityKeys.map((identityKey) => `i.identity_id = \"${escapeCypherString(identityKey)}\"`)\n  return {\n    id: 'identity_member_addresses',\n    query: [\n      'MATCH (i:Identity)-[:HAS_ADDRESS]->(m:Address)',\n      `WHERE ${predicates.join(' OR ')}`,\n      'RETURN i.identity_id AS identity_id, collect(m.address) AS member_addresses',\n      `LIMIT ${identityKeys.length}`,\n    ].join(' '),\n  }\n}\n\n/**\n * Resolve public tool address inputs to canonical identity keys.\n *\n * Inputs already in canonical 0x form (with or without the network prefix)\n * are derived locally as `<network>:<lowercase 0x form>`. Any other member\n * form (for example an SS58 substrate address) is resolved through the\n * indexed `(:Address {address})<-[:HAS_ADDRESS]-(:Identity)` lookup.\n * Inputs the graph cannot resolve are passed through unchanged.\n */\n// Resolves each raw input to its canonical identity_id via the graph's Address\n// node: (:Identity)-[:HAS_ADDRESS]->(:Address {address: $raw}). Inputs that do\n// not resolve (no matching Address/Identity in the active topology) are\n// OMITTED from the returned map -- callers must not fall back to treating the\n// raw input as an identity_id (network:<raw address> is never a valid\n// identity_id; identities are keyed network:<canonical form>). Use\n// resolved.has(input) to distinguish \"resolved to X\" from \"did not resolve\".\nexport async function resolveIdentityKeys(\n  remoteClient: Client,\n  network: string,\n  inputs: string[],\n  topologyScope: TopologyScope = DEFAULT_TOPOLOGY_SCOPE,\n): Promise<Map<string, string>> {\n  const resolved = new Map<string, string>()\n  const pendingAddressLookup: string[] = []\n  const pendingCanonicalCandidate = new Map<string, string>()\n  for (const input of [...new Set(inputs.map((value) => value.trim()).filter(Boolean))]) {\n    const canonical = canonicalIdentityKeyFor(network, memberFormOf(input, network))\n    if (canonical) pendingCanonicalCandidate.set(input, canonical)\n    else pendingAddressLookup.push(input)\n  }\n  if (pendingAddressLookup.length === 0 && pendingCanonicalCandidate.size === 0) return resolved\n\n  const addressQueries = pendingAddressLookup.map((input, index) => ({\n    input,\n    ...memberAddressResolutionQuery(`resolve_member_address_${index + 1}`, memberFormOf(input, network)),\n  }))\n  const canonicalInputs = [...pendingCanonicalCandidate.keys()]\n  const existenceQueries = canonicalInputs.map((input, index) => ({\n    input,\n    ...identityExistenceQuery(`resolve_identity_exists_${index + 1}`, pendingCanonicalCandidate.get(input)!),\n  }))\n  const batch = await callGraphBatch(\n    remoteClient,\n    network,\n    [...addressQueries, ...existenceQueries].map(({ id, query }) => ({ id, query })),\n    topologyScope,\n  )\n  const failures: QueryFailure[] = []\n  for (const { input, id } of addressQueries) {\n    const rows = optionalResultsFor(batch, id, failures)\n    const identityId = firstString(rows[0]?.['identity_id'])\n    if (identityId) resolved.set(input, identityId)\n  }\n  for (const { input, id } of existenceQueries) {\n    const rows = optionalResultsFor(batch, id, failures)\n    const identityId = firstString(rows[0]?.['identity_id'])\n    if (identityId) resolved.set(input, identityId)\n  }\n  return resolved\n}\n\ntype IdentityDisplayInfo = {\n  canonical_identity_key: string\n  address: string\n  member_addresses: string[]\n}\n\nfunction collectIdentityKeys(value: unknown, network: string, keys = new Set<string>()): Set<string> {\n  const prefix = `${network}:`\n  if (typeof value === 'string') {\n    if (value.startsWith(prefix)) keys.add(value)\n    return keys\n  }\n  if (Array.isArray(value)) {\n    for (const item of value) collectIdentityKeys(item, network, keys)\n    return keys\n  }\n  if (typeof value === 'object' && value !== null) {\n    for (const item of Object.values(value)) collectIdentityKeys(item, network, keys)\n  }\n  return keys\n}\n\nasync function identityDisplayMap(\n  remoteClient: Client,\n  network: string,\n  identityKeys: string[],\n  preferredByIdentity = new Map<string, string>(),\n  topologyScope: TopologyScope = DEFAULT_TOPOLOGY_SCOPE,\n): Promise<Map<string, IdentityDisplayInfo>> {\n  const uniqueKeys = [...new Set(identityKeys.filter((key) => key.startsWith(`${network}:`)))]\n  const memberRows = new Map<string, string[]>()\n  if (uniqueKeys.length > 0) {\n    try {\n      const batch = await callGraphBatch(remoteClient, network, [identityMemberAddressesQuery(uniqueKeys)], topologyScope)\n      for (const row of optionalResultsFor(batch, 'identity_member_addresses', [])) {\n        const identityKey = firstString(row['identity_id'])\n        if (!identityKey) continue\n        memberRows.set(identityKey, stringArrayValue(row['member_addresses']) ?? [])\n      }\n    } catch {\n      // Publicization is best-effort. Tool execution should not fail only\n      // because member-address decoration was unavailable.\n    }\n  }\n\n  return new Map(uniqueKeys.map((identityKey) => {\n    const preferred = preferredByIdentity.get(identityKey)\n    const members = memberRows.get(identityKey) ?? []\n    const address = preferred ? memberFormOf(preferred, network) : members[0] ?? memberFormOf(identityKey, network)\n    return [identityKey, {\n      canonical_identity_key: identityKey,\n      address,\n      member_addresses: members,\n    }]\n  }))\n}\n\nfunction replaceIdentityKeysDeep(value: unknown, displayByIdentity: Map<string, IdentityDisplayInfo>): unknown {\n  if (typeof value === 'string') return replaceIdentityKeysInText(value, displayByIdentity)\n  if (Array.isArray(value)) return value.map((item) => replaceIdentityKeysDeep(item, displayByIdentity))\n  if (typeof value !== 'object' || value === null) return value\n  return Object.fromEntries(\n    Object.entries(value).map(([key, entry]) => [key, replaceIdentityKeysDeep(entry, displayByIdentity)]),\n  )\n}\n\nfunction replaceIdentityKeysInText(value: string, displayByIdentity: Map<string, IdentityDisplayInfo>): string {\n  return [...displayByIdentity.entries()]\n    .sort((a, b) => b[0].length - a[0].length)\n    .reduce((text, [identityKey, info]) => text.replaceAll(identityKey, info.address), value)\n}\n\nfunction identityResolution(displayByIdentity: Map<string, IdentityDisplayInfo>): IdentityDisplayInfo[] {\n  return [...displayByIdentity.values()]\n    .sort((a, b) => a.address.localeCompare(b.address))\n}\n\nasync function publicizeIdentityResult<T extends {\n  summaryText: string\n  structuredContent: Record<string, unknown>\n  graphData: Record<string, unknown>\n}>(\n  remoteClient: Client,\n  network: string,\n  result: T,\n  preferredByIdentity = new Map<string, string>(),\n  topologyScope: TopologyScope = DEFAULT_TOPOLOGY_SCOPE,\n): Promise<T> {\n  const identityKeys = [\n    ...collectIdentityKeys(result.summaryText, network),\n    ...collectIdentityKeys(result.structuredContent, network),\n    ...collectIdentityKeys(result.graphData, network),\n  ]\n  const displayByIdentity = await identityDisplayMap(remoteClient, network, identityKeys, preferredByIdentity, topologyScope)\n  if (displayByIdentity.size === 0) return result\n  return {\n    ...result,\n    summaryText: replaceIdentityKeysInText(result.summaryText, displayByIdentity),\n    structuredContent: {\n      ...(replaceIdentityKeysDeep(result.structuredContent, displayByIdentity) as Record<string, unknown>),\n      identity_resolution: identityResolution(displayByIdentity),\n    },\n    graphData: replaceIdentityKeysDeep(result.graphData, displayByIdentity) as Record<string, unknown>,\n  }\n}\n\nfunction graphArray(graphData: Record<string, unknown>, key: string): Array<Record<string, unknown>> {\n  const value = graphData[key]\n  return Array.isArray(value) ? value.filter((item): item is Record<string, unknown> => typeof item === 'object' && item !== null && !Array.isArray(item)) : []\n}\n\nfunction addressProfileQuery(address: string, topologyScope: TopologyScope): { id: string; query: string } {\n  // risk_score/risk_level are a live_topology-only \"slim live risk verdict\" on\n  // :Identity (see ops/memgql/README.md); the archive_topology StarRocks\n  // mapping never defines them, so projecting them there hard-errors the\n  // whole query instead of nulling gracefully. Real risk scores for archive\n  // come from the separate USE facts query (addressRiskScoreQuery).\n  const riskFields = topologyScope === 'archive_topology' ? '' : ', a.risk_score AS live_risk_score, a.risk_level AS live_risk_level'\n  return {\n    id: 'address_profile',\n    query: [\n      `MATCH (a:Identity {identity_id: \"${escapeCypherString(address)}\"})`,\n      `RETURN a.identity_id AS address, a.labels AS display_labels, a.labels AS system_labels, a.is_exchange AS is_exchange${riskFields}`,\n      'LIMIT 1',\n    ].join(' '),\n  }\n}\n\nfunction memberAddressesQuery(address: string): { id: string; query: string } {\n  // No collect(): MemGQL translates collect() to MySQL's JSON_ARRAYAGG, which\n  // StarRocks rejects (memgraph/memgraph#4178, upstream, unfixed as of 0.6.3).\n  // Return one row per member address and aggregate client-side instead.\n  return {\n    id: 'member_addresses',\n    query: [\n      `MATCH (a:Identity {identity_id: \"${escapeCypherString(address)}\"})-[:HAS_ADDRESS]->(m:Address)`,\n      'RETURN m.address AS member_address',\n      'LIMIT 50',\n    ].join(' '),\n  }\n}\n\nfunction addressFeatureQuery(address: string): { id: string; query: string } {\n  return {\n    id: 'address_feature',\n    query: [\n      'USE facts',\n      `MATCH (a:Identity {identity_id: \"${escapeCypherString(address)}\"})-[:HAS_FEATURE]->(feature:AddressFeature)`,\n      'RETURN feature.degree_in AS degree_in, feature.degree_out AS degree_out, feature.degree_total AS degree_total, feature.tx_in_count AS tx_in_count, feature.tx_out_count AS tx_out_count, feature.tx_total_count AS tx_total_count, feature.total_volume_usd AS total_volume_usd, feature.total_in_usd AS total_in_usd, feature.total_out_usd AS total_out_usd, feature.net_flow_usd AS net_flow_usd, feature.first_activity_timestamp AS first_activity_timestamp, feature.last_activity_timestamp AS last_activity_timestamp, feature.activity_span_days AS activity_span_days',\n      'LIMIT 1',\n    ].join(' '),\n  }\n}\n\nfunction addressRiskScoreQuery(address: string): { id: string; query: string } {\n  return {\n    id: 'address_risk_score',\n    query: [\n      'USE facts',\n      `MATCH (a:Identity {identity_id: \"${escapeCypherString(address)}\"})-[:HAS_RISK_SCORE]->(risk:RiskScore)`,\n      'RETURN risk.risk_score AS ml_risk_score, risk.risk_level AS ml_risk_level, risk.window_days AS risk_window_days, risk.processing_date AS risk_processing_date, risk.xgboost_model_version AS xgboost_model_version, risk.gnn_model_version AS gnn_model_version, risk.shap_top_features AS shap_top_features',\n      'LIMIT 1',\n    ].join(' '),\n  }\n}\n\nfunction addressLabelRiskQuery(address: string): { id: string; query: string } {\n  return {\n    id: 'address_label_risk',\n    query: [\n      'USE facts',\n      `MATCH (a:Identity {identity_id: \"${escapeCypherString(address)}\"})-[:HAS_LABEL]->(label:AddressLabel)`,\n      'RETURN label.label AS label, label.risk_level AS risk_level, label.trust_level AS trust_level, label.confidence_score AS confidence_score, label.source AS source, label.entity_type AS entity_type, label.updated_timestamp AS updated_timestamp',\n      // Deterministic subset: an unordered LIMIT let the surfaced labels —\n      // and therefore the derived risk level — flap between runs for\n      // label-heavy identities.\n      'ORDER BY label.updated_timestamp DESC',\n      'LIMIT 10',\n    ].join(' '),\n  }\n}\n\nfunction flowEdgeMap(variableName: string): string {\n  return `{amount_usd_sum: ${variableName}.amount_usd_sum, tx_count: ${variableName}.tx_count, first_seen_timestamp: ${variableName}.first_seen_timestamp, last_seen_timestamp: ${variableName}.last_seen_timestamp, first_tx_id: ${variableName}.first_tx_id, last_tx_id: ${variableName}.last_tx_id}`\n}\n\nfunction pathNodeMap(variableName: string, topologyScope: TopologyScope): string {\n  // See addressProfileQuery: risk_score/risk_level aren't in the archive_topology\n  // Identity mapping, so they must be omitted from path_nodes on that scope.\n  const riskFields = topologyScope === 'archive_topology' ? '' : `, risk_score: ${variableName}.risk_score, risk_level: ${variableName}.risk_level`\n  return `{address: ${variableName}.identity_id, labels: ${variableName}.labels, system_labels: ${variableName}.labels, is_exchange: ${variableName}.is_exchange${riskFields}}`\n}\n\nfunction exchangeOutflowQueries(address: string, topologyScope: TopologyScope): Array<{ id: string; query: string }> {\n  return Array.from({ length: 3 }, (_, index) => exchangeOutflowQueryAtDepth(address, index + 1, topologyScope))\n}\n\nfunction exchangeOutflowQueryAtDepth(address: string, depth: number, topologyScope: TopologyScope): { id: string; query: string } {\n  const intermediateVariables = Array.from({ length: Math.max(depth - 1, 0) }, (_, index) => `n${index + 1}`)\n  const nodeVariables = ['a', ...intermediateVariables, 'exchange']\n  const edgeVariables = Array.from({ length: depth }, (_, index) => `r${index + 1}`)\n  const relationshipChain = edgeVariables.map((edgeVariable, index) => {\n    const targetVariable = index === edgeVariables.length - 1 ? 'exchange' : intermediateVariables[index]!\n    return `-[${edgeVariable}:FLOWS_TO]->(${targetVariable}:Identity)`\n  }).join('')\n  const intermediatePredicates = intermediateVariables.map((nodeVariable) => `${nodeVariable}.is_exchange IS NULL`)\n  const depositVariable = nodeVariables[nodeVariables.length - 2]!\n  const terminalEdgeVariable = edgeVariables[edgeVariables.length - 1]!\n  return {\n    id: `exchange_outflows_${depth}`,\n    query: [\n      `MATCH (a:Identity {identity_id: \"${escapeCypherString(address)}\"})${relationshipChain}`,\n      `WHERE a.identity_id <> exchange.identity_id AND exchange.is_exchange IS NOT NULL${intermediatePredicates.length > 0 ? ` AND ${intermediatePredicates.join(' AND ')}` : ''}`,\n      `RETURN \"outflow\" AS direction, exchange.identity_id AS exchange_address, exchange.labels AS exchange_display_labels, exchange.labels AS exchange_system_labels, ${depositVariable}.identity_id AS deposit_address, ${depth} AS hops, ${terminalEdgeVariable}.amount_usd_sum AS amount_usd_sum, ${terminalEdgeVariable}.tx_count AS tx_count, ${terminalEdgeVariable}.first_seen_timestamp AS first_seen_timestamp, ${terminalEdgeVariable}.last_seen_timestamp AS last_seen_timestamp, [${nodeVariables.map((nodeVariable) => `${nodeVariable}.identity_id`).join(', ')}] AS addresses, [${nodeVariables.map((nodeVariable) => pathNodeMap(nodeVariable, topologyScope)).join(', ')}] AS path_nodes, [${edgeVariables.map(flowEdgeMap).join(', ')}] AS edge_props`,\n      'ORDER BY hops ASC',\n      'LIMIT 200',\n    ].join(' '),\n  }\n}\n\nfunction exchangeInflowQueries(address: string, topologyScope: TopologyScope): Array<{ id: string; query: string }> {\n  return Array.from({ length: 3 }, (_, index) => exchangeInflowQueryAtDepth(address, index + 1, topologyScope))\n}\n\nfunction exchangeInflowQueryAtDepth(address: string, depth: number, topologyScope: TopologyScope): { id: string; query: string } {\n  const intermediateVariables = Array.from({ length: Math.max(depth - 1, 0) }, (_, index) => `n${index + 1}`)\n  const nodeVariables = ['exchange', ...intermediateVariables, 'a']\n  const edgeVariables = Array.from({ length: depth }, (_, index) => `r${index + 1}`)\n  const relationshipChain = edgeVariables.map((edgeVariable, index) => {\n    const targetVariable = index === edgeVariables.length - 1 ? 'a' : intermediateVariables[index]!\n    return `-[${edgeVariable}:FLOWS_TO]->(${targetVariable}:Identity)`\n  }).join('')\n  const intermediatePredicates = intermediateVariables.map((nodeVariable) => `${nodeVariable}.is_exchange IS NULL`)\n  const withdrawalVariable = nodeVariables[1]!\n  const terminalEdgeVariable = edgeVariables[edgeVariables.length - 1]!\n  return {\n    id: `exchange_inflows_${depth}`,\n    query: [\n      `MATCH (exchange:Identity)${relationshipChain}`,\n      `WHERE a.identity_id = \"${escapeCypherString(address)}\" AND a.identity_id <> exchange.identity_id AND exchange.is_exchange IS NOT NULL${intermediatePredicates.length > 0 ? ` AND ${intermediatePredicates.join(' AND ')}` : ''}`,\n      `RETURN \"inflow\" AS direction, exchange.identity_id AS exchange_address, exchange.labels AS exchange_display_labels, exchange.labels AS exchange_system_labels, ${withdrawalVariable}.identity_id AS withdrawal_address, ${depth} AS hops, ${terminalEdgeVariable}.amount_usd_sum AS amount_usd_sum, ${terminalEdgeVariable}.tx_count AS tx_count, ${terminalEdgeVariable}.first_seen_timestamp AS first_seen_timestamp, ${terminalEdgeVariable}.last_seen_timestamp AS last_seen_timestamp, [${nodeVariables.map((nodeVariable) => `${nodeVariable}.identity_id`).join(', ')}] AS addresses, [${nodeVariables.map((nodeVariable) => pathNodeMap(nodeVariable, topologyScope)).join(', ')}] AS path_nodes, [${edgeVariables.map(flowEdgeMap).join(', ')}] AS edge_props`,\n      'ORDER BY hops ASC',\n      'LIMIT 200',\n    ].join(' '),\n  }\n}\n\nfunction connectionProbeQuery(address: string, compareAddress: string): { id: string; query: string } {\n  return {\n    id: 'connection_probe',\n    query: [\n      `MATCH (a:Identity {identity_id: \"${escapeCypherString(address)}\"})-[r:FLOWS_TO]-(b:Identity {identity_id: \"${escapeCypherString(compareAddress)}\"})`,\n      'RETURN [a.identity_id, b.identity_id] AS addresses, 1 AS hops',\n      'LIMIT 5',\n    ].join(' '),\n  }\n}\n\nfunction formatExchangeRows(rows: Array<Record<string, unknown>>): string[] {\n  return rows.map((row) => {\n    const direction = String(row['direction'] ?? 'flow')\n    const exchange = String(row['exchange_address'] ?? '')\n    const amount = row['amount_usd_sum'] ?? ''\n    const hops = row['hops'] ?? ''\n    return `- ${direction}: ${exchange} (${hops} hop(s), amount_usd_sum ${amount})`\n  })\n}\n\nfunction numberValue(value: unknown): number | undefined {\n  if (typeof value === 'number' && Number.isFinite(value)) return value\n  if (typeof value === 'string' && value.trim()) {\n    const parsed = Number(value)\n    return Number.isFinite(parsed) ? parsed : undefined\n  }\n  return undefined\n}\n\nfunction isExchangeFlag(value: unknown): boolean {\n  if (value === true) return true\n  if (value === false || value === null || value === undefined) return false\n  if (typeof value === 'string') {\n    const normalized = value.trim().toLowerCase()\n    return normalized === 'true' || normalized === '1'\n  }\n  if (typeof value === 'number') return value === 1\n  return false\n}\n\nfunction hasExactExchangeLabel(labels: string[] | undefined): boolean {\n  return (labels ?? []).some((label) => label.trim().toLowerCase() === 'exchange')\n}\n\nfunction firstNumber(...values: unknown[]): number | undefined {\n  for (const value of values) {\n    const parsed = numberValue(value)\n    if (parsed !== undefined) return parsed\n  }\n  return undefined\n}\n\nfunction firstString(...values: unknown[]): string | undefined {\n  for (const value of values) {\n    if (typeof value === 'string' && value.trim()) return value.trim()\n  }\n  return undefined\n}\n\nfunction riskLevelFromScore(score: number): string {\n  if (score >= 0.85) return 'critical'\n  if (score >= 0.7) return 'high'\n  if (score >= 0.4) return 'medium'\n  return 'low'\n}\n\nfunction riskRecommendation(level: string): string {\n  if (level === 'critical' || level === 'high') return 'Escalate for manual review.'\n  if (level === 'medium') return 'Review exchange exposure and counterparties before clearing.'\n  return 'No stored risk signal found; continue with normal monitoring.'\n}\n\nfunction riskDrivers(\n  profile: Record<string, unknown>,\n  labelRows: Array<Record<string, unknown>>,\n  exchangeRows: Array<Record<string, unknown>>,\n): string[] {\n  const drivers: string[] = []\n  const shapDrivers = stringArrayValue(profile['shap_top_features'])\n  if (shapDrivers?.length) drivers.push(`Top model features: ${shapDrivers.join(', ')}`)\n\n  const riskLabels = labelRows\n    .map((row) => firstString(row['label']))\n    .filter((label): label is string => Boolean(label))\n  if (riskLabels.length > 0) drivers.push(`Labels: ${[...new Set(riskLabels)].join('; ')}`)\n\n  const outflowCount = exchangeRows.filter((row) => row['direction'] === 'outflow').length\n  const inflowCount = exchangeRows.filter((row) => row['direction'] === 'inflow').length\n  if (outflowCount > 0) drivers.push(`Forward bounded search reached ${outflowCount} exchange path(s).`)\n  if (inflowCount > 0) drivers.push(`Backward bounded search found ${inflowCount} source exchange path(s).`)\n\n  return [...new Set(drivers)]\n}\n\nconst RISK_LEVEL_ORDER = ['critical', 'high', 'medium', 'low'] as const\n\nfunction strongestLabelRiskLevel(labelRows: Array<Record<string, unknown>>): string | undefined {\n  const levels = labelRows\n    .map((row) => firstString(row['risk_level'])?.toLowerCase())\n    .filter((level): level is string => Boolean(level && (RISK_LEVEL_ORDER as readonly string[]).includes(level)))\n  if (levels.length === 0) return undefined\n  return RISK_LEVEL_ORDER.find((candidate) => levels.includes(candidate))\n}\n\nfunction riskScoreSources(profile: Record<string, unknown>, labelRows: Array<Record<string, unknown>>): Array<Record<string, unknown>> {\n  const sources: Array<Record<string, unknown>> = []\n  if (numberValue(profile['ml_risk_score']) !== undefined) {\n    sources.push({\n      family: 'ml_risk_score',\n      layer: 'facts',\n      view: 'facts_risk_scores_view',\n      xgboost_model_version: profile['xgboost_model_version'],\n      gnn_model_version: profile['gnn_model_version'],\n      processing_date: profile['risk_processing_date'],\n      window_days: profile['risk_window_days'],\n    })\n  }\n  if (labelRows.length > 0) {\n    sources.push({\n      family: 'label_risk',\n      layer: 'facts',\n      view: 'facts_address_labels_view',\n      labels: labelRows.map((row) => ({\n        label: row['label'],\n        risk_level: row['risk_level'],\n        trust_level: row['trust_level'],\n        confidence_score: row['confidence_score'],\n        source: row['source'],\n      })),\n    })\n  }\n  return sources\n}\n\nfunction terminalEdgeProperties(row: Record<string, unknown>): Record<string, unknown> | undefined {\n  const edgeProps = Array.isArray(row['edge_props']) ? row['edge_props'] as Array<Record<string, unknown>> : []\n  return edgeProps[edgeProps.length - 1]\n}\n\nfunction enrichExchangeRows(rows: Array<Record<string, unknown>>): Array<Record<string, unknown>> {\n  return rows.map((row) => {\n    const terminal = terminalEdgeProperties(row)\n    if (!terminal) return row\n    return {\n      ...row,\n      amount_usd_sum: row['amount_usd_sum'] ?? terminal['amount_usd_sum'],\n      tx_count: row['tx_count'] ?? terminal['tx_count'],\n      first_seen_timestamp: row['first_seen_timestamp'] ?? terminal['first_seen_timestamp'],\n      last_seen_timestamp: row['last_seen_timestamp'] ?? terminal['last_seen_timestamp'],\n      first_tx_id: row['first_tx_id'] ?? terminal['first_tx_id'],\n      last_tx_id: row['last_tx_id'] ?? terminal['last_tx_id'],\n    }\n  })\n}\n\nconst FALLBACK_SHARED_TX_COUNT = 1000\nconst FALLBACK_SHARED_USD_SUM = 5_000_000\nconst FALLBACK_SHARED_DAMPING = 0.1\nconst FALLBACK_VALUE_SATURATION_USD = 1_000_000\nconst FALLBACK_BASE_SCORE = 0.1\nconst FALLBACK_MAX_SCORE = 0.6\n\n/**\n * Score exchange exposure when no ML risk score exists. Topology-grain:\n * log-scaled USD volume across exchange rows, with shared/omnibus edges\n * (high tx_count or USD throughput) dampened, bounded in (0, 0.6] so a\n * fallback can never impersonate a high ML score band.\n */\nexport function exchangeExposureFallbackScore(exchangeRows: Array<Record<string, unknown>>): number {\n  if (exchangeRows.length === 0) return 0\n  let weightedUsd = 0\n  for (const row of exchangeRows) {\n    const usd = numberValue(row['amount_usd_sum']) ?? 0\n    const txCount = numberValue(row['tx_count']) ?? 0\n    const shared = txCount >= FALLBACK_SHARED_TX_COUNT || usd >= FALLBACK_SHARED_USD_SUM\n    weightedUsd += shared ? usd * FALLBACK_SHARED_DAMPING : usd\n  }\n  const capped = Math.min(weightedUsd, FALLBACK_VALUE_SATURATION_USD)\n  const factor = Math.log10(1 + capped) / Math.log10(1 + FALLBACK_VALUE_SATURATION_USD)\n  return Math.min(FALLBACK_MAX_SCORE, FALLBACK_BASE_SCORE + (FALLBACK_MAX_SCORE - FALLBACK_BASE_SCORE) * factor)\n}\n\nexport function riskAssessment(\n  profile: Record<string, unknown>,\n  labelRows: Array<Record<string, unknown>>,\n  exchangeRows: Array<Record<string, unknown>>,\n): Record<string, unknown> {\n  const mlRiskScore = firstNumber(profile['ml_risk_score'])\n  // UNSCORED is the model's explicit abstention (calibrated-scoring release):\n  // the score exists for transparency but carries no stance — deriving a\n  // severity band from it would silently launder an abstention into a\n  // confident verdict (typically \"low\"). Fall back to labels/exchange\n  // exposure and say so.\n  const mlAbstained = isUnscoredRiskLevel(profile['ml_risk_level'])\n  const labelRiskLevel = strongestLabelRiskLevel(labelRows)\n  const usableMlScore = mlAbstained ? undefined : mlRiskScore\n  const score = usableMlScore ?? exchangeExposureFallbackScore(exchangeRows)\n  let level = labelRiskLevel ?? (mlAbstained && exchangeRows.length === 0 ? 'unscored' : riskLevelFromScore(score))\n  const drivers = riskDrivers(profile, labelRows, exchangeRows)\n  if (mlAbstained) drivers.push('ml_abstained: ML verdict is UNSCORED (insufficient labeled graph context); level derived from labels/exchange exposure only')\n  // Labels are curated truth and stay first — but a lower-severity label\n  // must never SUPPRESS a more severe usable ML band. Failing toward\n  // \"looks safe\" is the one direction an AML triage tool may not fail.\n  const usableMlBand = usableMlScore !== undefined ? riskLevelFromScore(usableMlScore) : undefined\n  if (\n    labelRiskLevel &&\n    usableMlBand &&\n    riskSeverityRank(usableMlBand) > riskSeverityRank(labelRiskLevel)\n  ) {\n    level = usableMlBand\n    drivers.push(`ml_label_divergence: usable ML band ${usableMlBand} exceeds strongest label level ${labelRiskLevel}; reporting the more severe band — review the label`)\n  }\n  return {\n    level,\n    score,\n    ...(mlRiskScore !== undefined ? { ml_risk_score: mlRiskScore } : {}),\n    ...(mlAbstained ? { ml_verdict: 'unscored' } : {}),\n    confidence: (usableMlScore !== undefined || labelRiskLevel) ? 'high' : exchangeRows.length > 0 ? 'medium' : 'low',\n    recommendation: level === 'unscored' ? 'Model abstained and no label/exchange signal found; gather more context before clearing.' : riskRecommendation(level),\n    drivers,\n    sources: riskScoreSources(profile, labelRows),\n  }\n}\n\nfunction formatRiskScore(score: unknown): string {\n  const parsed = numberValue(score)\n  if (parsed === undefined) return String(score ?? 'unknown')\n  return Number.isInteger(parsed) ? parsed.toString() : parsed.toFixed(2)\n}\n\nfunction stringArrayValue(value: unknown): string[] | undefined {\n  if (Array.isArray(value)) return value.map(String)\n  if (typeof value === 'string' && value.trim()) return [value]\n  return undefined\n}\n\nfunction restoreSystemLabels(graph: Record<string, unknown>, rawNodes: Array<Record<string, unknown>>): Record<string, unknown> {\n  if (!Array.isArray(graph['nodes'])) return graph\n  const labelsByAddress = new Map(rawNodes\n    .map((node) => [typeof node['address'] === 'string' ? node['address'] : typeof node['id'] === 'string' ? node['id'] : '', stringArrayValue(node['system_labels'])] as const)\n    .filter((entry): entry is readonly [string, string[]] => Boolean(entry[0]) && Array.isArray(entry[1]) && entry[1].length > 0))\n  return {\n    ...graph,\n    nodes: graph['nodes'].map((node) => {\n      if (typeof node !== 'object' || node === null || Array.isArray(node)) return node\n      const record = node as Record<string, unknown>\n      const address = typeof record['address'] === 'string' ? record['address'] : typeof record['id'] === 'string' ? record['id'] : ''\n      const systemLabels = labelsByAddress.get(address)\n      return systemLabels ? { ...record, system_labels: systemLabels } : record\n    }),\n  }\n}\n\nfunction buildRiskGraph(address: string, profile: Record<string, unknown>, rows: Array<Record<string, unknown>>, network: string): Record<string, unknown> {\n  const nodes = new Map<string, Record<string, unknown>>()\n  nodes.set(address, {\n    id: address,\n    address,\n    node_type: 'address',\n    labels: stringArrayValue(profile['display_labels']) ?? [],\n    ...(stringArrayValue(profile['system_labels']) ? { system_labels: stringArrayValue(profile['system_labels']) } : {}),\n    ...(stringArrayValue(profile['member_addresses'])?.length ? { member_addresses: stringArrayValue(profile['member_addresses']) } : {}),\n    ...(numberValue(profile['live_risk_score']) !== undefined ? { risk_score: numberValue(profile['live_risk_score']) } : {}),\n    ...(firstString(profile['live_risk_level']) ? { risk_level: firstString(profile['live_risk_level']) } : {}),\n    roles: ['subject'],\n  })\n  const edges: Array<Record<string, unknown>> = []\n  const mergeNode = (entry: string, metadata?: Record<string, unknown>) => {\n    const existing = nodes.get(entry) ?? { id: entry, address: entry, node_type: 'address', labels: [] }\n    const labels = stringArrayValue(metadata?.['labels']) ?? existing['labels']\n    const systemLabels = stringArrayValue(metadata?.['system_labels']) ?? existing['system_labels']\n    const memberAddresses = stringArrayValue(metadata?.['member_addresses']) ?? existing['member_addresses']\n    const riskScore = numberValue(metadata?.['risk_score']) ?? existing['risk_score']\n    const riskLevel = normalizeRiskLevel(firstString(metadata?.['risk_level'])) ?? existing['risk_level']\n    nodes.set(entry, {\n      ...existing,\n      labels,\n      ...(systemLabels ? { system_labels: systemLabels } : {}),\n      ...(Array.isArray(memberAddresses) && memberAddresses.length > 0 ? { member_addresses: memberAddresses } : {}),\n      ...(riskScore !== undefined ? { risk_score: riskScore } : {}),\n      ...(riskLevel ? { risk_level: riskLevel } : {}),\n    })\n  }\n  for (const row of rows) {\n    const rawPath = Array.isArray(row['path']) ? row['path'] : row['addresses']\n    const path = Array.isArray(rawPath) ? rawPath.map(String) : []\n    const pathNodes = Array.isArray(row['path_nodes']) ? row['path_nodes'] as Array<Record<string, unknown>> : []\n    for (let index = 0; index < path.length; index += 1) {\n      const entry = path[index]!\n      mergeNode(entry, pathNodes[index])\n    }\n    const exchange = typeof row['exchange_address'] === 'string' ? row['exchange_address'] : ''\n    if (exchange) {\n      const displayLabels = stringArrayValue(row['exchange_display_labels']) ?? []\n      const systemLabels = stringArrayValue(row['exchange_system_labels']) ?? stringArrayValue(row['exchange_labels']) ?? []\n      nodes.set(exchange, {\n        id: exchange,\n        address: exchange,\n        node_type: 'address',\n        labels: displayLabels,\n        ...(systemLabels.length > 0 ? { system_labels: systemLabels } : {}),\n        roles: ['exchange'],\n      })\n    }\n    for (let index = 0; index < path.length - 1; index += 1) {\n      const edgeProps = Array.isArray(row['edge_props']) ? row['edge_props'] as Array<Record<string, unknown>> : []\n      const edge = edgeProps[index] ?? row\n      edges.push({\n        source: path[index],\n        target: path[index + 1],\n        edge_type: 'flows_to',\n        usd_amount: edge['amount_usd_sum'] ?? 0,\n        amount_usd_sum: edge['amount_usd_sum'] ?? 0,\n        tx_count: edge['tx_count'] ?? 0,\n        first_tx_id: edge['first_tx_id'],\n        last_tx_id: edge['last_tx_id'],\n        direction: row['direction'],\n      })\n    }\n  }\n  const rawNodes = [...nodes.values()]\n  return restoreSystemLabels(normalizeGraphPayload({\n    schema: 'chain-insights.graph.v1',\n    nodes: rawNodes,\n    edges,\n    flows: [],\n    edge_anchors: [],\n    metadata: { address, network, generated_at: new Date().toISOString() },\n  }), rawNodes)\n}\n\nexport async function addressRisk(remoteClient: Client, options: AddressRiskOptions): Promise<{\n  summaryText: string\n  structuredContent: Record<string, unknown>\n  graphData: Record<string, unknown>\n}> {\n  const inputAddress = options.address.trim()\n  const network = options.network.trim()\n  const compareInput = options.compareAddress?.trim() ?? ''\n  const topologyScope = options.topologyScope ?? DEFAULT_TOPOLOGY_SCOPE\n  if (!inputAddress) throw new Error('address is required')\n  if (!network) throw new Error('network is required')\n  const resolvedKeys = await resolveIdentityKeys(remoteClient, network, [inputAddress, ...(compareInput ? [compareInput] : [])], topologyScope)\n  if (!resolvedKeys.has(inputAddress)) {\n    return {\n      summaryText: `Address risk for ${network}:${inputAddress}\\n\\nUnresolved: no Identity/Address found for \"${inputAddress}\" in ${topologyScope}. The address may not have on-chain activity in this network or topology scope; try topology_scope=archive_topology for full history.`,\n      structuredContent: {\n        schema: 'chain-insights.result.v1',\n        tool: 'aml_address_risk',\n        facts: {\n          subject: { network, addresses: [inputAddress], topology_scope: topologyScope },\n          unresolved: [inputAddress],\n        },\n      },\n      graphData: { schema: 'chain-insights.graph.v1', nodes: [], edges: [], flows: [], edge_anchors: [], metadata: { address: inputAddress, network, generated_at: new Date().toISOString() } },\n    }\n  }\n  const address = resolvedKeys.get(inputAddress)!\n  const compareUnresolved = compareInput !== '' && !resolvedKeys.has(compareInput)\n  const compareAddress = compareInput && !compareUnresolved ? resolvedKeys.get(compareInput)! : ''\n  const preferredByIdentity = new Map<string, string>([\n    [address, inputAddress],\n    ...(compareAddress ? [[compareAddress, compareInput] as [string, string]] : []),\n  ])\n\n  const queries = [\n    addressProfileQuery(address, topologyScope),\n    memberAddressesQuery(address),\n    addressFeatureQuery(address),\n    addressRiskScoreQuery(address),\n    addressLabelRiskQuery(address),\n    ...exchangeOutflowQueries(address, topologyScope),\n    ...exchangeInflowQueries(address, topologyScope),\n    ...(compareAddress ? [connectionProbeQuery(address, compareAddress)] : [{ id: 'connection_probe', query: 'MATCH (n:Identity {identity_id: \"__chain_insights_noop__\"}) RETURN n.identity_id AS noop LIMIT 0' }]),\n  ]\n  const batch = await callGraphBatch(remoteClient, network, queries, topologyScope)\n  const partialQueryFailures: QueryFailure[] = []\n  const memberAddressRows = optionalResultsFor(batch, 'member_addresses', partialQueryFailures)\n  const memberAddressesFromRows = memberAddressRows.map((row) => firstString(row['member_address'])).filter((value): value is string => Boolean(value))\n  const profile: Record<string, unknown> = {\n    address,\n    ...(optionalResultsFor(batch, 'address_profile', partialQueryFailures)[0] ?? {}),\n    ...(memberAddressesFromRows.length > 0 ? { member_addresses: memberAddressesFromRows } : {}),\n    ...(optionalResultsFor(batch, 'address_feature', partialQueryFailures)[0] ?? {}),\n    ...(optionalResultsFor(batch, 'address_risk_score', partialQueryFailures)[0] ?? {}),\n  }\n  const labelRows = optionalResultsFor(batch, 'address_label_risk', partialQueryFailures)\n  const outflows = enrichExchangeRows(optionalResultsWithPrefix(batch, 'exchange_outflows_', partialQueryFailures))\n  const inflows = enrichExchangeRows(optionalResultsWithPrefix(batch, 'exchange_inflows_', partialQueryFailures))\n  const connections = compareAddress ? optionalResultsFor(batch, 'connection_probe', partialQueryFailures) : []\n  const exchangeRows = [...outflows, ...inflows]\n  const graphData = buildRiskGraph(address, profile, exchangeRows, network)\n  const risk = riskAssessment(profile, labelRows, exchangeRows)\n  const memberAddresses = stringArrayValue(profile['member_addresses']) ?? []\n  const liveRiskScore = numberValue(profile['live_risk_score'])\n  const liveRiskLevel = firstString(profile['live_risk_level'])\n  const liveNodeVerdict = liveRiskScore !== undefined || liveRiskLevel\n    ? {\n        ...(liveRiskScore !== undefined ? { risk_score: liveRiskScore } : {}),\n        ...(liveRiskLevel ? { risk_level: liveRiskLevel } : {}),\n        source: 'live_topology_node',\n      }\n    : undefined\n\n  const lines = [\n    `Address risk for ${network}:${address}`,\n    '',\n    `Risk: ${risk['level']} (${formatRiskScore(risk['score'])})`,\n    `Confidence: ${risk['confidence']}`,\n    `Recommendation: ${risk['recommendation']}`,\n    ...(liveNodeVerdict ? [`Live node triage: ${liveRiskLevel ?? 'unknown'} (${formatRiskScore(liveRiskScore)})`] : []),\n    `Member addresses: ${memberAddresses.join(', ') || 'unknown'}.`,\n    `Graph degree: in ${profile['degree_in'] ?? 'unknown'}, out ${profile['degree_out'] ?? 'unknown'}.`,\n    '',\n    'Exchange behavior',\n    exchangeRows.length > 0 ? formatExchangeRows(exchangeRows).join('\\n') : '- No exchange inflow/outflow paths found in bounded search.',\n  ]\n  if (Array.isArray(risk['drivers']) && risk['drivers'].length > 0) {\n    lines.push('', 'Risk drivers', risk['drivers'].map((driver) => `- ${driver}`).join('\\n'))\n  }\n  if (compareAddress) {\n    lines.push('', `Connection compare target: ${compareAddress}`, connections.length > 0 ? `Connection paths found: ${connections.length}` : 'Connection paths found: 0')\n  }\n  if (compareUnresolved) {\n    lines.push('', `Unresolved compare_address: no Identity/Address found for \"${compareInput}\" in ${topologyScope}; comparison skipped.`)\n  }\n  if (partialQueryFailures.length > 0) {\n    lines.push('', 'Partial query failures', partialQueryFailures.map((failure) => `- ${failure.id}: ${failure.error}`).join('\\n'))\n  }\n  const summaryText = lines.join('\\n')\n  const baseResult = {\n    summaryText,\n    structuredContent: {\n      schema: 'chain-insights.result.v1',\n      tool: 'aml_address_risk',\n      facts: {\n        subject: {\n          network,\n          addresses: compareAddress ? [address, compareAddress] : [address],\n          ...(memberAddresses.length > 0 ? { member_addresses: memberAddresses } : {}),\n          topology_scope: topologyScope,\n        },\n        risk: {\n          ...risk,\n          ...(liveNodeVerdict ? { live_node: liveNodeVerdict } : {}),\n        },\n        exchange_behavior: {\n          outflows,\n          inflows,\n        },\n        connection: compareAddress ? { compare_address: compareAddress, paths: connections } : undefined,\n        unresolved: compareUnresolved ? [compareInput] : undefined,\n        partial_query_errors: partialQueryFailures.length > 0 ? partialQueryFailures : undefined,\n      },\n      artifacts: statelessArtifacts(),\n      evidence: [{\n        evidence_type: 'tool_summary',\n        summary: `aml_address_risk ${address} completed for ${network}`,\n      }],\n    },\n    graphData,\n  }\n  const publicResult = await publicizeIdentityResult(remoteClient, network, baseResult, preferredByIdentity, topologyScope)\n  const publicSubject = publicResult.structuredContent.facts as Record<string, unknown> | undefined\n  const publicSubjectAddresses = (publicSubject?.subject as Record<string, unknown> | undefined)?.addresses\n  const publicSubjectAddress = Array.isArray(publicSubjectAddresses) && typeof publicSubjectAddresses[0] === 'string'\n    ? publicSubjectAddresses[0]\n    : memberFormOf(inputAddress, network)\n  const publicCompareAddress = Array.isArray(publicSubjectAddresses) && typeof publicSubjectAddresses[1] === 'string'\n    ? publicSubjectAddresses[1]\n    : compareAddress\n  const artifacts = options.writeArtifacts ? await writeAddressRiskArtifacts(\n    network,\n    publicSubjectAddress,\n    publicCompareAddress,\n    publicResult.graphData,\n    exchangeRows,\n    publicResult.summaryText,\n  ) : statelessArtifacts()\n  const evidence = artifactEvidence(artifacts)\n\n  return {\n    summaryText: publicResult.summaryText,\n    structuredContent: {\n      ...publicResult.structuredContent,\n      artifacts,\n      evidence: [...evidence, {\n        evidence_type: 'tool_summary',\n        summary: `aml_address_risk ${inputAddress} completed for ${network}`,\n      }],\n    },\n    graphData: publicResult.graphData,\n  }\n}\n\ntype TraceSeedRole = 'victim' | 'suspect' | 'deposit'\ntype TraceToolName = 'aml_trace_victim_funds' | 'aml_trace_suspect_funds' | 'aml_trace_deposit_sources'\ntype TraceRole =\n  | 'seed_victim'\n  | 'seed_suspect'\n  | 'seed_deposit'\n  | 'candidate_victim'\n  | 'candidate_suspect'\n  | 'candidate_intermediate'\n  | 'candidate_deposit'\n  | 'exchange'\n  | 'unknown'\n\nexport interface TraceVictimFundsOptions {\n  victimAddresses: string | string[]\n  knownSuspectAddresses?: string | string[]\n  network: string\n  incidentTimestampMs?: number\n  timeRange?: { from_ms?: number; to_ms?: number }\n  maxHops?: number\n  perAddressLimit?: number\n  minAmountSum?: number\n  writeArtifacts?: boolean\n  topologyScope?: TopologyScope\n}\n\nexport interface TraceSuspectFundsOptions {\n  suspectAddresses: string | string[]\n  network: string\n  incidentTimestampMs?: number\n  timeRange?: { from_ms?: number; to_ms?: number }\n  maxHops?: number\n  perAddressLimit?: number\n  minAmountSum?: number\n  writeArtifacts?: boolean\n  topologyScope?: TopologyScope\n}\n\nexport interface TraceDepositSourcesOptions {\n  depositAddresses: string | string[]\n  network: string\n  timeRange?: { from_ms?: number; to_ms?: number }\n  maxHops?: number\n  minAmountSum?: number\n  writeArtifacts?: boolean\n  topologyScope?: TopologyScope\n}\n\ntype TraceToolResult = {\n  summaryText: string\n  structuredContent: Record<string, unknown>\n  graphData: Record<string, unknown>\n}\n\ntype TraceRunRole = 'victim' | 'suspect'\ntype TraceRun = { role: TraceRunRole; address: string; result: TraceFundsResult }\ntype TraceAddressAccumulator = {\n  address: string\n  roles: Set<TraceRole>\n  labels: string[]\n  is_exchange?: boolean\n  confidence: 'low' | 'medium' | 'high'\n  rationale: string[]\n}\n\nfunction uniqueStrings(values: Array<string | undefined>): string[] {\n  return [...new Set(values.filter((value): value is string => typeof value === 'string' && value.length > 0))]\n}\n\nfunction clampInt(value: number | undefined, fallback: number, min: number, max: number): number {\n  if (!Number.isFinite(value)) return fallback\n  return Math.max(min, Math.min(max, Math.trunc(value as number)))\n}\n\nfunction traceActivityWindow(incidentTimestampMs: number | undefined, timeRange: { from_ms?: number; to_ms?: number } | undefined): TraceActivityWindow | undefined {\n  const fromMs = timeRange?.from_ms ?? incidentTimestampMs\n  if (fromMs === undefined) return undefined\n  return { fromMs, ...(timeRange?.to_ms !== undefined ? { toMs: timeRange.to_ms } : {}) }\n}\n\nfunction graphRecords(graphData: Record<string, unknown>, key: string): Array<Record<string, unknown>> {\n  const value = graphData[key]\n  return Array.isArray(value)\n    ? value.filter((item): item is Record<string, unknown> => typeof item === 'object' && item !== null && !Array.isArray(item))\n    : []\n}\n\nfunction normalizeTraceGraphData(runs: TraceRun[], network: string): Record<string, unknown> {\n  return normalizeGraphPayload({\n    schema: 'chain-insights.graph.v1',\n    nodes: runs.flatMap((run) => graphRecords(run.result.graphData, 'nodes')),\n    edges: runs.flatMap((run) => graphRecords(run.result.graphData, 'edges')),\n    flows: runs.flatMap((run) => graphRecords(run.result.graphData, 'flows')),\n    deposits: runs.flatMap((run) => graphRecords(run.result.graphData, 'deposits').map((item) => ({ ...item, run_role: run.role, run_address: run.address }))),\n    source_matches: runs.flatMap((run) => graphRecords(run.result.graphData, 'source_matches').map((item) => ({ ...item, run_role: run.role, run_address: run.address }))),\n    reverse_leads: runs.flatMap((run) => graphRecords(run.result.graphData, 'reverse_leads').map((item) => ({ ...item, run_role: run.role, run_address: run.address }))),\n    edge_anchors: [],\n    metadata: {\n      network,\n      generated_at: new Date().toISOString(),\n      trace_tools: true,\n    },\n  })\n}\n\nfunction traceArtifactPointersFromRun(run: TraceFundsResult | undefined): Record<string, unknown> {\n  if (!run) return {}\n  if (!Object.values(run.files).some((value) => value.length > 0)) {\n    return {\n      artifacts_written: false,\n      artifact_mode: 'stateless',\n    }\n  }\n  return {\n    graph_json: run.files.graph,\n    graph_html: run.files.graphHtml,\n    table_json: run.files.compactEvidence,\n    flows_csv: run.files.table,\n    table_html: run.files.tableHtml,\n    report_md: run.files.report,\n  }\n}\n\nfunction traceArtifactSummary(artifacts: Record<string, string>): string {\n  return [\n    'Files written:',\n    `- compact evidence JSON: ${artifacts['table_json'] ?? ''}`,\n    `- graph JSON: ${artifacts['graph_json'] ?? ''}`,\n    `- graph HTML: ${artifacts['graph_html'] ?? ''}`,\n    `- flows CSV: ${artifacts['flows_csv'] ?? ''}`,\n    `- table HTML: ${artifacts['table_html'] ?? ''}`,\n    `- report: ${artifacts['report_md'] ?? ''}`,\n  ].join('\\n')\n}\n\nfunction stripTraceFileSections(summaryText: string): string {\n  const lines = summaryText.split('\\n')\n  const kept: string[] = []\n  for (let index = 0; index < lines.length; index += 1) {\n    const line = lines[index]\n    if (line === 'Files written: disabled by stateless proxy mode.') {\n      if (lines[index + 1] === '') index += 1\n      continue\n    }\n    if (line === 'Files written:') {\n      index += 1\n      while (index < lines.length && lines[index]?.startsWith('- ')) {\n        index += 1\n      }\n      if (lines[index] !== '') {\n        index -= 1\n      }\n      continue\n    }\n    kept.push(line)\n  }\n  return kept.join('\\n').replace(/\\n{3,}/g, '\\n\\n').trimEnd()\n}\n\nfunction withTraceArtifactSummary(summaryText: string, artifacts: Record<string, string>): string {\n  const cleaned = stripTraceFileSections(summaryText)\n  return [\n    cleaned,\n    '',\n    traceArtifactSummary(artifacts),\n  ].filter((part) => part.length > 0).join('\\n')\n}\n\nfunction toCsvValue(value: unknown): string {\n  return value === undefined || value === null ? '' : String(value)\n}\n\nfunction subjectNodeForExchangeRow(row: Record<string, unknown>, fallbackAddress: string): string {\n  return String(\n    row['direction'] === 'inflow'\n      ? row['withdrawal_address'] ?? row['deposit_address'] ?? fallbackAddress\n      : row['deposit_address'] ?? row['withdrawal_address'] ?? fallbackAddress,\n  )\n}\n\nfunction buildAddressRiskTableHtml(tool: string, network: string, rows: Array<Record<string, unknown>>, subject: string): string {\n  const headers = ['direction', 'exchange_address', 'subject_path_node', 'hops', 'amount_usd_sum', 'tx_count'] as const\n  const body = rows.map((row) => {\n    const exchangeAddress = String(row['exchange_address'] ?? '')\n    const subjectNode = subjectNodeForExchangeRow(row, subject)\n    const rowValues = [\n      row['direction'] ?? '',\n      exchangeAddress,\n      subjectNode,\n      row['hops'] ?? '',\n      row['amount_usd_sum'] ?? '',\n      row['tx_count'] ?? '',\n    ]\n    return `<tr>${rowValues.map((value) => `<td>${htmlEscape(toCsvValue(value))}</td>`).join('')}</tr>`\n  }).join('\\n')\n  return `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>${htmlEscape(tool)} Risk Table</title>\n<style>\n  :root { color-scheme: dark; font-family: Inter, ui-sans-serif, system-ui; background: #0b0d12; color: #f4f2ea; }\n  body { margin: 0; background: #0b0d12; color: #f4f2ea; }\n  main { padding: 24px; }\n  h1 { font-size: 20px; margin: 0 0 8px; font-weight: 650; }\n  table { border-collapse: collapse; width: 100%; min-width: 900px; }\n  th, td { border-bottom: 1px solid rgba(255,255,255,.08); padding: 8px 10px; text-align: left; }\n  th { position: sticky; top: 0; background: #161a24; color: #f2dda6; font-weight: 600; }\n</style>\n</head>\n<body>\n<main>\n  <h1>${htmlEscape(tool)} Table</h1>\n  <div>Network: <strong>${htmlEscape(network)}</strong></div>\n  <div>Generated: <strong>${htmlEscape(new Date().toISOString())}</strong></div>\n  <table>\n    <thead><tr>${headers.map((header) => `<th>${htmlEscape(header)}</th>`).join('')}</tr></thead>\n    <tbody>${body}</tbody>\n  </table>\n</main>\n</body>\n</html>\n`\n}\n\nasync function writeAddressRiskArtifacts(\n  network: string,\n  address: string,\n  compareAddress: string | undefined,\n  graphData: Record<string, unknown>,\n  exchangeRows: Array<Record<string, unknown>>,\n  summaryText: string,\n): Promise<Record<string, string>> {\n  const paths = workspaceOutputPaths()\n  await Promise.all([\n    mkdir(paths.reportsRoot, { recursive: true }),\n    mkdir(paths.reportGraphsRoot, { recursive: true }),\n    mkdir(paths.reportTablesRoot, { recursive: true }),\n  ])\n  const safeNetwork = network.replace(/[^A-Za-z0-9._-]+/g, '_')\n  const safeAddress = address.replace(/[^A-Za-z0-9._-]+/g, '_')\n  const slug = `${new Date().toISOString().replace(/[-:]/g, '').replace(/\\.\\d{3}Z$/, 'Z')}_aml_address_risk_${safeNetwork}_${safeAddress}`\n  const graphPath = path.join(paths.reportGraphsRoot, `${slug}.graph.json`)\n  const tableJsonPath = path.join(paths.reportTablesRoot, `${slug}.compact-evidence.json`)\n  const csvPath = path.join(paths.reportTablesRoot, `${slug}.flows.csv`)\n  const tableHtmlPath = path.join(paths.reportsRoot, `${slug}.table.html`)\n  const reportPath = path.join(paths.reportsRoot, `${slug}.aml-address-report.md`)\n  const graphHtmlPath = path.join(paths.reportsRoot, `${slug}.graph.html`)\n  const { generateInlineGraphHtml } = await import('../viz/html-generator.js')\n  const header = [\n    'direction',\n    'exchange_address',\n    'subject_path_node',\n    'hops',\n    'amount_usd_sum',\n    'tx_count',\n  ]\n  const csv = [\n    header.join(','),\n    ...exchangeRows.map((row) => {\n      const exchangeAddress = String(row['exchange_address'] ?? '')\n      const subjectPathNode = subjectNodeForExchangeRow(row, address)\n      return [\n        row['direction'] ?? '',\n        exchangeAddress,\n        subjectPathNode,\n        row['hops'] ?? '',\n        row['amount_usd_sum'] ?? '',\n        row['tx_count'] ?? '',\n      ].map((value) => JSON.stringify(String(value))).join(',')\n    }),\n  ].join('\\n') + '\\n'\n  const evidence = {\n    schema: 'chain-insights.trace.v1',\n    tool: 'aml_address_risk',\n    network,\n    input: {\n      address,\n      ...(compareAddress ? { compare_address: compareAddress } : {}),\n    },\n    profile: {\n      exchange_rows: exchangeRows.map((row) => ({\n        direction: row['direction'],\n        exchange_address: row['exchange_address'],\n        subject_node: subjectNodeForExchangeRow(row, address),\n        hops: row['hops'],\n        amount_usd_sum: row['amount_usd_sum'],\n        tx_count: row['tx_count'],\n      })),\n      report_summary: summaryText,\n    },\n  }\n  await writeFile(graphPath, JSON.stringify(graphData, null, 2) + '\\n', { mode: 0o600 })\n  await writeFile(tableJsonPath, JSON.stringify(evidence, null, 2) + '\\n', { mode: 0o600 })\n  await writeFile(csvPath, csv, { mode: 0o600 })\n  await writeFile(tableHtmlPath, buildAddressRiskTableHtml('aml_address_risk', network, exchangeRows, address), { mode: 0o600 })\n  await writeFile(graphHtmlPath, generateInlineGraphHtml(graphData), { mode: 0o600 })\n  await writeFile(\n    reportPath,\n    [\n      `# Address Risk Report (${network}:${address})`,\n      `- Graph JSON: ${graphPath}`,\n      `- Table JSON: ${tableJsonPath}`,\n      `- CSV: ${csvPath}`,\n      `- Report HTML: ${tableHtmlPath}`,\n      `- Graph HTML: ${graphHtmlPath}`,\n      '',\n      summaryText,\n    ].join('\\n'),\n    { mode: 0o600 },\n  )\n\n  return {\n    graph_json: graphPath,\n    graph_html: graphHtmlPath,\n    table_json: tableJsonPath,\n    flows_csv: csvPath,\n    table_html: tableHtmlPath,\n    report_md: reportPath,\n  }\n}\n\n\nfunction statelessArtifacts(): Record<string, unknown> {\n  return {\n    artifacts_written: false,\n    artifact_mode: 'stateless',\n  }\n}\n\nfunction artifactEvidence(artifacts: Record<string, unknown>): Array<Record<string, unknown>> {\n  return Object.entries(artifacts)\n    .filter((entry): entry is [string, string] => entry[0] !== 'artifact_mode' && typeof entry[1] === 'string' && entry[1].length > 0)\n    .map(([kind, filePath]) => ({\n      evidence_type: 'artifact_pointer',\n      path: filePath,\n      summary: `${kind} artifact`,\n    }))\n}\n\nfunction traceEdgesForCsv(structuredContent: Record<string, unknown>): Array<Record<string, unknown>> {\n  const edges = structuredContent['edges']\n  return Array.isArray(edges)\n    ? edges.filter((edge): edge is Record<string, unknown> => typeof edge === 'object' && edge !== null && !Array.isArray(edge))\n    : []\n}\n\nfunction buildTraceTableHtml(tool: string, network: string, result: TraceToolResult): string {\n  const headers = ['edge_id', 'from_address', 'to_address', 'amount_usd_sum', 'tx_count', 'first_tx_id', 'last_tx_id'] as const\n  const body = traceEdgesForCsv(result.structuredContent).map((row) => {\n    const rowValues = headers.map((header) => row[header] ?? '')\n    return `<tr>${rowValues.map((value) => `<td>${htmlEscape(toCsvValue(value))}</td>`).join('')}</tr>`\n  }).join('\\n')\n  return `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>${htmlEscape(tool)} Trace Table</title>\n<style>\n  :root { color-scheme: dark; font-family: Inter, ui-sans-serif, system-ui; background: #0b0d12; color: #f4f2ea; }\n  body { margin: 0; background: #0b0d12; color: #f4f2ea; }\n  main { padding: 24px; }\n  h1 { font-size: 20px; margin: 0 0 8px; font-weight: 650; }\n  table { border-collapse: collapse; width: 100%; min-width: 900px; }\n  th, td { border-bottom: 1px solid rgba(255,255,255,.08); padding: 8px 10px; text-align: left; }\n  th { position: sticky; top: 0; background: #161a24; color: #f2dda6; font-weight: 600; }\n</style>\n</head>\n<body>\n<main>\n  <h1>${htmlEscape(tool)} Trace Table</h1>\n  <div>Network: <strong>${htmlEscape(network)}</strong></div>\n  <div>Generated: <strong>${htmlEscape(new Date().toISOString())}</strong></div>\n  <table>\n    <thead><tr>${headers.map((header) => `<th>${htmlEscape(header)}</th>`).join('')}</tr></thead>\n    <tbody>${body}</tbody>\n  </table>\n</main>\n</body>\n</html>\n`\n}\n\nasync function writeTraceArtifacts(tool: TraceToolName, network: string, result: TraceToolResult): Promise<{ artifacts: Record<string, string>; summaryText: string }> {\n  const paths = workspaceOutputPaths()\n  await Promise.all([\n    mkdir(paths.reportsRoot, { recursive: true }),\n    mkdir(paths.reportGraphsRoot, { recursive: true }),\n    mkdir(paths.reportTablesRoot, { recursive: true }),\n  ])\n  const slug = `${new Date().toISOString().replace(/[-:]/g, '').replace(/\\.\\d{3}Z$/, 'Z')}_${tool}`\n  const graphPath = path.join(paths.reportGraphsRoot, `${slug}.graph.json`)\n  const tableJsonPath = path.join(paths.reportTablesRoot, `${slug}.compact-evidence.json`)\n  const csvPath = path.join(paths.reportTablesRoot, `${slug}.flows.csv`)\n  const tableHtmlPath = path.join(paths.reportsRoot, `${slug}.table.html`)\n  const reportPath = path.join(paths.reportsRoot, `${slug}.trace-report.md`)\n  const graphHtmlPath = path.join(paths.reportsRoot, `${slug}.graph.html`)\n  const artifacts = {\n    graph_json: graphPath,\n    graph_html: graphHtmlPath,\n    table_json: tableJsonPath,\n    flows_csv: csvPath,\n    table_html: tableHtmlPath,\n    report_md: reportPath,\n  }\n  const existingEvidence = Array.isArray(result.structuredContent['evidence'])\n    ? result.structuredContent['evidence'].filter((entry): entry is Record<string, unknown> => typeof entry === 'object' && entry !== null && !Array.isArray(entry))\n    : []\n  const structuredForArtifact = {\n    ...result.structuredContent,\n    artifacts,\n    evidence: [\n      ...existingEvidence.filter((entry) => entry['evidence_type'] !== 'artifact_pointer'),\n      ...artifactEvidence(artifacts),\n    ],\n  }\n  const summaryText = withTraceArtifactSummary(result.summaryText, artifacts)\n  const { generateInlineGraphHtml } = await import('../viz/html-generator.js')\n  const csvHeaders = ['edge_id', 'from_address', 'to_address', 'amount_usd_sum', 'tx_count', 'first_tx_id', 'last_tx_id']\n  const csv = [\n    csvHeaders.join(','),\n    ...traceEdgesForCsv(result.structuredContent).map((row) => csvHeaders\n      .map((header) => JSON.stringify(String(row[header] ?? '')))\n      .join(',')),\n  ].join('\\n') + '\\n'\n  await writeFile(graphPath, JSON.stringify(result.graphData, null, 2) + '\\n', { mode: 0o600 })\n  await writeFile(tableJsonPath, JSON.stringify(structuredForArtifact, null, 2) + '\\n', { mode: 0o600 })\n  await writeFile(csvPath, csv, { mode: 0o600 })\n  await writeFile(tableHtmlPath, buildTraceTableHtml(tool, network, result), { mode: 0o600 })\n  await writeFile(reportPath, summaryText + '\\n', { mode: 0o600 })\n  await writeFile(graphHtmlPath, generateInlineGraphHtml(result.graphData), { mode: 0o600 })\n  return { artifacts, summaryText }\n}\n\nasync function publicizeTraceResult(\n  remoteClient: Client,\n  network: string,\n  result: TraceToolResult,\n  preferredByIdentity: Map<string, string>,\n  writeArtifacts: boolean,\n  topologyScope: TopologyScope = DEFAULT_TOPOLOGY_SCOPE,\n): Promise<TraceToolResult> {\n  const publicResult = await publicizeIdentityResult(remoteClient, network, result, preferredByIdentity, topologyScope)\n  if (!writeArtifacts) return publicResult\n  const tool = typeof publicResult.structuredContent['tool'] === 'string'\n    ? publicResult.structuredContent['tool'] as TraceToolName\n    : 'aml_trace_victim_funds'\n  const { artifacts, summaryText } = await writeTraceArtifacts(tool, network, publicResult)\n  const existingEvidence = Array.isArray(publicResult.structuredContent['evidence'])\n    ? publicResult.structuredContent['evidence'].filter((entry): entry is Record<string, unknown> => typeof entry === 'object' && entry !== null && !Array.isArray(entry))\n    : []\n  return {\n    ...publicResult,\n    summaryText,\n    structuredContent: {\n      ...publicResult.structuredContent,\n      artifacts,\n      evidence: [\n        ...existingEvidence.filter((entry) => entry['evidence_type'] !== 'artifact_pointer'),\n        ...artifactEvidence(artifacts),\n      ],\n    },\n  }\n}\n\nfunction traceAddressRoleForSeed(seedRole: TraceSeedRole): TraceRole {\n  if (seedRole === 'victim') return 'seed_victim'\n  if (seedRole === 'suspect') return 'seed_suspect'\n  return 'seed_deposit'\n}\n\nfunction addTraceAddress(\n  addresses: Map<string, TraceAddressAccumulator>,\n  address: string,\n  role: TraceRole,\n  rationale: string,\n  labels: string[] = [],\n): void {\n  if (!address) return\n  const existing = addresses.get(address)\n  if (existing) {\n    existing.roles.add(role)\n    existing.labels = uniqueStrings([...existing.labels, ...labels])\n    if (role === 'exchange') existing.is_exchange = true\n    if (!existing.rationale.includes(rationale)) existing.rationale.push(rationale)\n    return\n  }\n  addresses.set(address, {\n    address,\n    roles: new Set([role]),\n    labels,\n    is_exchange: role === 'exchange' ? true : undefined,\n    confidence: role.startsWith('seed_') || role === 'exchange' ? 'high' : 'medium',\n    rationale: [rationale],\n  })\n}\n\nfunction edgeKey(from: string, to: string): string {\n  return `${from}\\u0000${to}`\n}\n\nfunction traceResultFromFundRuns(\n  tool: Extract<TraceToolName, 'aml_trace_victim_funds' | 'aml_trace_suspect_funds'>,\n  seedRole: Extract<TraceSeedRole, 'victim' | 'suspect'>,\n  network: string,\n  runs: TraceRun[],\n  options: {\n    incidentTimestampMs?: number\n    timeRange?: { from_ms?: number; to_ms?: number }\n    activityWindow?: TraceActivityWindow\n    maxHops?: number\n    unresolved?: string[]\n    topologyScope?: TopologyScope\n    archiveHint?: string[]\n    } = {},\n): { summaryText: string; structuredContent: Record<string, unknown>; graphData: Record<string, unknown> } {\n  const graphData = normalizeTraceGraphData(runs, network)\n  const flows = graphRecords(graphData, 'flows')\n  const deposits = graphRecords(graphData, 'deposits')\n  const sourceMatches = graphRecords(graphData, 'source_matches')\n  const reverseLeads = graphRecords(graphData, 'reverse_leads')\n  const addresses = new Map<string, TraceAddressAccumulator>()\n  for (const run of runs) {\n    addTraceAddress(addresses, run.address, traceAddressRoleForSeed(seedRole), `${seedRole} seed provided by caller`)\n  }\n\n  const edgeIdsByPair = new Map<string, string>()\n  const edges = flows.map((flow, index) => {\n    const src = typeof flow['src'] === 'string' ? flow['src'] : ''\n    const dst = typeof flow['dst'] === 'string' ? flow['dst'] : ''\n    const edgeId = `e${index + 1}`\n    edgeIdsByPair.set(edgeKey(src, dst), edgeId)\n    const terminalExchange = flow['terminal_exchange'] === true\n    addTraceAddress(addresses, src, runs.some((run) => run.address === src) ? traceAddressRoleForSeed(seedRole) : 'candidate_intermediate', 'Address appears in traced FLOWS_TO path')\n    addTraceAddress(addresses, dst, terminalExchange ? 'exchange' : 'candidate_intermediate', terminalExchange ? 'Terminal exchange endpoint reached' : 'Address appears in traced FLOWS_TO path')\n    return {\n      edge_id: edgeId,\n      from_address: src,\n      to_address: dst,\n      edge_type: 'FLOWS_TO',\n      amount_usd_sum: numberValue(flow['amount_usd_sum']),\n      tx_count: numberValue(flow['tx_count']),\n      first_tx_id: typeof flow['first_tx_id'] === 'string' ? flow['first_tx_id'] : undefined,\n      last_tx_id: typeof flow['last_tx_id'] === 'string' ? flow['last_tx_id'] : undefined,\n    }\n  }).filter((edge) => edge.from_address && edge.to_address)\n\n  const paths = deposits.map((deposit, index) => {\n    const depositAddress = typeof deposit['address'] === 'string'\n      ? deposit['address']\n      : typeof deposit['deposit_address'] === 'string' ? deposit['deposit_address'] : ''\n    const exchangeAddress = typeof deposit['exchangeAddress'] === 'string'\n      ? deposit['exchangeAddress']\n      : typeof deposit['exchange_address'] === 'string' ? deposit['exchange_address'] : ''\n    const pathAddresses = stringArrayValue(deposit['path']) ?? [\n      typeof deposit['run_address'] === 'string' ? deposit['run_address'] : runs[0]?.address ?? '',\n      depositAddress,\n      exchangeAddress,\n    ].filter(Boolean)\n    addTraceAddress(addresses, depositAddress, 'candidate_deposit', 'Penultimate address before an exchange endpoint')\n    if (exchangeAddress) addTraceAddress(addresses, exchangeAddress, 'exchange', 'Exchange endpoint reached')\n    const edgeIds: string[] = []\n    for (let offset = 0; offset < pathAddresses.length - 1; offset += 1) {\n      const id = edgeIdsByPair.get(edgeKey(pathAddresses[offset]!, pathAddresses[offset + 1]!))\n      if (id) edgeIds.push(id)\n    }\n    return {\n      path_id: `p${index + 1}`,\n      direction: 'forward',\n      source: pathAddresses[0] ?? '',\n      target: exchangeAddress || depositAddress,\n      addresses: pathAddresses,\n      edge_ids: edgeIds,\n      hops: numberValue(deposit['hops']) ?? Math.max(pathAddresses.length - 1, 0),\n      terminal_role: exchangeAddress ? 'exchange' : 'deposit',\n      amount_usd_sum: numberValue(deposit['amount_usd_sum']),\n    }\n  })\n\n  const depositAddresses = uniqueStrings(deposits.map((deposit) => (\n    typeof deposit['address'] === 'string' ? deposit['address'] : typeof deposit['deposit_address'] === 'string' ? deposit['deposit_address'] : undefined\n  )))\n  const exchangeAddresses = uniqueStrings(deposits.map((deposit) => (\n    typeof deposit['exchangeAddress'] === 'string' ? deposit['exchangeAddress'] : typeof deposit['exchange_address'] === 'string' ? deposit['exchange_address'] : undefined\n  )))\n  const convergence = [...new Map(depositAddresses.map((address) => {\n    const pathIds = paths.filter((path) => path.addresses.includes(address)).map((path) => path.path_id)\n    return [address, {\n      address,\n      role: 'candidate_deposit',\n      path_ids: pathIds,\n      reason: pathIds.length > 1 ? 'Multiple traced paths converge into this deposit candidate.' : 'Single traced path reached this deposit candidate.',\n    }]\n  })).values()].filter((entry) => entry.path_ids.length > 1)\n  const candidateLabels = depositAddresses.map((address) => ({\n    address,\n    candidate_label: 'candidate_deposit',\n    confidence: 'medium',\n    evidence_path_ids: paths.filter((path) => path.addresses.includes(address)).map((path) => path.path_id),\n    reason: 'Penultimate address before an exchange endpoint in bounded FLOWS_TO trace.',\n    promote_to_core_label: false,\n  }))\n  const runArtifacts = runs.map((run, index) => ({\n    run_id: `run_${index + 1}`,\n    role: run.role,\n    address: run.address,\n    ...traceArtifactPointersFromRun(run.result),\n  }))\n  const artifacts = {\n    ...traceArtifactPointersFromRun(runs[0]?.result),\n    runs: runArtifacts,\n  }\n  const artifactEvidenceEntries = runs.flatMap((run) => artifactEvidence(traceArtifactPointersFromRun(run.result))\n    .map((entry) => ({ ...entry, run_role: run.role, address: run.address })))\n  const recommendedNextTools = depositAddresses.length > 0\n    ? ['aml_trace_deposit_sources', 'aml_address_risk']\n    : ['aml_address_risk', 'graph_query_batch']\n\n  const structuredContent = {\n    schema: 'chain-insights.trace.v1',\n    tool,\n    network,\n    input: {\n      addresses: runs.map((run) => run.address),\n      seed_role: seedRole,\n      ...(options.incidentTimestampMs !== undefined ? { incident_timestamp_ms: options.incidentTimestampMs } : {}),\n      ...(options.timeRange ? { time_range: options.timeRange } : {}),\n      time_filter: options.activityWindow\n        ? { from_ms: options.activityWindow.fromMs, ...(options.activityWindow.toMs !== undefined ? { to_ms: options.activityWindow.toMs } : {}) }\n        : 'none',\n      max_hops: options.maxHops ?? 3,\n      topology_scope: options.topologyScope ?? DEFAULT_TOPOLOGY_SCOPE,\n    },\n    summary: {\n      seed_count: runs.length,\n      unresolved_count: options.unresolved?.length ?? 0,\n      path_count: paths.length,\n      edge_count: edges.length,\n      candidate_suspect_count: seedRole === 'suspect' ? runs.length : 0,\n      candidate_intermediate_count: [...addresses.values()].filter((entry) => entry.roles.has('candidate_intermediate')).length,\n      candidate_deposit_count: depositAddresses.length,\n      exchange_count: exchangeAddresses.length,\n    },\n    unresolved: options.unresolved ?? [],\n    addresses: [...addresses.values()].map((entry) => ({\n      address: entry.address,\n      roles: [...entry.roles],\n      ...(entry.labels.length > 0 ? { labels: entry.labels } : {}),\n      ...(entry.is_exchange !== undefined ? { is_exchange: entry.is_exchange } : {}),\n      confidence: entry.confidence,\n      rationale: entry.rationale,\n    })),\n    edges,\n    paths,\n    convergence,\n    exchange_exposure: deposits.map((deposit) => ({\n      deposit_address: typeof deposit['address'] === 'string' ? deposit['address'] : deposit['deposit_address'],\n      exchange_address: typeof deposit['exchangeAddress'] === 'string' ? deposit['exchangeAddress'] : deposit['exchange_address'],\n      path_ids: paths.filter((path) => path.addresses.includes(String(deposit['address'] ?? deposit['deposit_address'] ?? ''))).map((path) => path.path_id),\n    })),\n    deposit_funding: {\n      source_exchange_paths: sourceMatches.map((match) => ({\n        deposit_address: match['deposit_address'],\n        source_exchange: match['source_exchange'],\n        source_labels: match['source_labels'],\n        hops: match['hops'],\n        path: match['path'],\n        reason: 'Deposit candidate upstream cluster is exchange-funded (topology-grain CEX-to-CEX structure).',\n      })),\n      reverse_leads: reverseLeads.map((lead) => ({\n        address: lead['address'],\n        deposit_address: lead['deposit_address'],\n        labels: lead['labels'],\n        amount_usd: lead['amount_usd'],\n        reason: lead['reason'],\n      })),\n    },\n    candidate_labels: candidateLabels,\n    artifacts,\n    evidence: [\n      ...artifactEvidenceEntries,\n    ],\n    continuation: {\n      candidate_deposit_addresses: depositAddresses,\n      candidate_suspect_addresses: seedRole === 'suspect' ? runs.map((run) => run.address) : [],\n      candidate_victim_addresses: [],\n      recommended_next_tools: recommendedNextTools,\n      ...(sourceMatches.length > 0 ? { deposit_funding_note: 'One or more deposit candidates are exchange-funded upstream; consider aml_trace_deposit_sources on those deposits.' } : {}),\n    },\n    warnings: [\n      ...(depositAddresses.length === 0 ? ['No exchange deposit candidates were connected in the queried topology.'] : []),\n      ...(options.unresolved && options.unresolved.length > 0 ? [`${options.unresolved.length} input address(es) did not resolve to a known Identity and were not traced: ${options.unresolved.join(', ')}.`] : []),\n      ...runs.flatMap((run) => run.result.tracebackWarnings ?? []),\n      ...(options.archiveHint ?? []),\n    ],\n  }\n\n  return {\n    summaryText: [\n      `${seedRole === 'victim' ? 'Trace victim funds' : 'Trace suspect funds'} complete for ${network}`,\n      ...(options.unresolved && options.unresolved.length > 0\n        ? [`Unresolved (no matching Identity/Address): ${options.unresolved.join(', ')}`]\n        : []),\n      '',\n      ...runs.map((run) => `## ${run.role}: ${run.address}\\n${run.result.summaryText}`),\n    ].join('\\n'),\n    structuredContent,\n    graphData,\n  }\n}\n\nexport async function traceVictimFunds(\n  remoteClient: Client,\n  config: Pick<InvestigatorConfig, 'dataDir' | 'serverPort'>,\n  options: TraceVictimFundsOptions,\n): Promise<TraceToolResult> {\n  const network = options.network.trim()\n  const victimInputs = parseAddressList(options.victimAddresses)\n  const knownSuspects = parseAddressList(options.knownSuspectAddresses)\n  if (!network) throw new Error('network is required')\n  if (victimInputs.length < 1) throw new Error('victim_addresses must contain at least 1 address')\n  if (victimInputs.length > 5) throw new Error('victim_addresses cannot exceed 5 addresses')\n  if (knownSuspects.length > 5) throw new Error('known_suspect_addresses cannot exceed 5 addresses')\n  const topologyScope = options.topologyScope ?? DEFAULT_TOPOLOGY_SCOPE\n  const resolvedVictims = await resolveIdentityKeys(remoteClient, network, victimInputs, topologyScope)\n  const unresolvedVictims = victimInputs.filter((input) => !resolvedVictims.has(input))\n  const victims = [...new Set(victimInputs.filter((input) => resolvedVictims.has(input)).map((input) => resolvedVictims.get(input)!))]\n  const preferredByIdentity = new Map(victimInputs.filter((input) => resolvedVictims.has(input)).map((input) => [resolvedVictims.get(input)!, input] as [string, string]))\n  const activityWindow = traceActivityWindow(options.incidentTimestampMs, options.timeRange)\n\n  const runs: TraceRun[] = []\n  for (const address of victims) {\n    runs.push({\n      role: 'victim',\n      address,\n      result: await runFundFlowProbe(remoteClient, config, {\n        seedAddress: address,\n        network,\n        maxHops: options.maxHops,\n        perAddressLimit: options.perAddressLimit,\n        minAmountSum: options.minAmountSum,\n        activityWindow,\n        includeDepositTraceback: true,\n        evidenceSource: 'aml_trace_victim_funds',\n        writeArtifacts: false,\n        topologyScope,\n      }),\n    })\n  }\n  const foundNothing = runs.length > 0 && runs.every((run) => graphRecords(run.result.graphData, 'flows').length === 0)\n  const archiveHint = await archiveRetryHint(remoteClient, network, topologyScope, foundNothing)\n  const result = traceResultFromFundRuns('aml_trace_victim_funds', 'victim', network, runs, {\n    incidentTimestampMs: options.incidentTimestampMs,\n    timeRange: options.timeRange,\n    activityWindow,\n    maxHops: options.maxHops,\n    unresolved: unresolvedVictims,\n    topologyScope,\n    archiveHint,\n  })\n  return publicizeTraceResult(remoteClient, network, result, preferredByIdentity, options.writeArtifacts !== false, topologyScope)\n}\n\nexport async function traceSuspectFunds(\n  remoteClient: Client,\n  config: Pick<InvestigatorConfig, 'dataDir' | 'serverPort'>,\n  options: TraceSuspectFundsOptions,\n): Promise<TraceToolResult> {\n  const network = options.network.trim()\n  const suspectInputs = parseAddressList(options.suspectAddresses)\n  if (!network) throw new Error('network is required')\n  if (suspectInputs.length < 1) throw new Error('suspect_addresses must contain at least 1 address')\n  if (suspectInputs.length > 5) throw new Error('suspect_addresses cannot exceed 5 addresses')\n  const topologyScope = options.topologyScope ?? DEFAULT_TOPOLOGY_SCOPE\n  const resolvedSuspects = await resolveIdentityKeys(remoteClient, network, suspectInputs, topologyScope)\n  const unresolvedSuspects = suspectInputs.filter((input) => !resolvedSuspects.has(input))\n  const suspects = [...new Set(suspectInputs.filter((input) => resolvedSuspects.has(input)).map((input) => resolvedSuspects.get(input)!))]\n  const preferredByIdentity = new Map(suspectInputs.filter((input) => resolvedSuspects.has(input)).map((input) => [resolvedSuspects.get(input)!, input] as [string, string]))\n  const activityWindow = traceActivityWindow(options.incidentTimestampMs, options.timeRange)\n\n  const runs: TraceRun[] = []\n  for (const address of suspects) {\n    runs.push({\n      role: 'suspect',\n      address,\n      result: await runFundFlowProbe(remoteClient, config, {\n        seedAddress: address,\n        network,\n        maxHops: options.maxHops,\n        perAddressLimit: options.perAddressLimit,\n        minAmountSum: options.minAmountSum,\n        activityWindow,\n        includeDepositTraceback: true,\n        evidenceSource: 'aml_trace_suspect_funds',\n        writeArtifacts: false,\n        topologyScope,\n      }),\n    })\n  }\n  const foundNothing = runs.length > 0 && runs.every((run) => graphRecords(run.result.graphData, 'flows').length === 0)\n  const archiveHint = await archiveRetryHint(remoteClient, network, topologyScope, foundNothing)\n  const result = traceResultFromFundRuns('aml_trace_suspect_funds', 'suspect', network, runs, {\n    incidentTimestampMs: options.incidentTimestampMs,\n    timeRange: options.timeRange,\n    activityWindow,\n    maxHops: options.maxHops,\n    unresolved: unresolvedSuspects,\n    topologyScope,\n    archiveHint,\n  })\n  return publicizeTraceResult(remoteClient, network, result, preferredByIdentity, options.writeArtifacts !== false, topologyScope)\n}\n\nconst REVERSE_DEPOSIT_SOURCES_LIMIT = 500\n\nfunction reverseDepositSourceQueryAtDepth(\n  depositAddresses: string[],\n  depth: number,\n  minAmountSum: number,\n  window: TraceActivityWindow | undefined,\n  topologyScope: TopologyScope,\n): { id: string; query: string } {\n  const intermediateVariables = Array.from({ length: Math.max(depth - 1, 0) }, (_, index) => `n${index + 1}`)\n  const nodeVariables = ['source', ...intermediateVariables, 'deposit']\n  const edgeVariables = Array.from({ length: depth }, (_, index) => `r${index + 1}`)\n  const relationshipChain = edgeVariables.map((edgeVariable, index) => {\n    const targetVariable = index === edgeVariables.length - 1 ? 'deposit' : intermediateVariables[index]!\n    return `-[${edgeVariable}:FLOWS_TO]->(${targetVariable}:Identity)`\n  }).join('')\n  const depositPredicates = depositAddresses.map((address) => `deposit.identity_id = \"${escapeCypherString(address)}\"`)\n  const nonExchangePredicates = ['source', ...intermediateVariables, 'deposit'].map((nodeVariable) => `${nodeVariable}.is_exchange IS NULL`)\n  const amountPredicates = minAmountSum > 0 ? edgeVariables.map((edgeVariable) => `${edgeVariable}.amount_usd_sum >= ${minAmountSum}`) : []\n  const windowPredicates = activityWindowPredicates(edgeVariables, window)\n  return {\n    id: `reverse_deposit_sources_${depth}`,\n    query: [\n      `MATCH (source:Identity)${relationshipChain}`,\n      `WHERE (${depositPredicates.join(' OR ')}) AND source.identity_id <> deposit.identity_id AND ${[...nonExchangePredicates, ...amountPredicates, ...windowPredicates].join(' AND ')}`,\n      `RETURN DISTINCT source.identity_id AS source_address, source.is_exchange AS source_is_exchange, deposit.identity_id AS deposit_address, deposit.is_exchange AS deposit_is_exchange, ${depth} AS hop, [${nodeVariables.map((nodeVariable) => `${nodeVariable}.identity_id`).join(', ')}] AS addresses, [${nodeVariables.map((nodeVariable) => pathNodeMap(nodeVariable, topologyScope)).join(', ')}] AS path_nodes, [${edgeVariables.map(flowEdgeMap).join(', ')}] AS edge_props`,\n      `LIMIT ${REVERSE_DEPOSIT_SOURCES_LIMIT}`,\n    ].join(' '),\n  }\n}\n\nfunction rowNodeIsExchange(value: unknown): boolean {\n  if (typeof value !== 'object' || value === null || Array.isArray(value)) return false\n  const record = value as Record<string, unknown>\n  return isExchangeFlag(record['is_exchange']) ||\n    hasExactExchangeLabel(stringArrayValue(record['labels'])) ||\n    hasExactExchangeLabel(stringArrayValue(record['system_labels']))\n}\n\nfunction reverseDepositSourceRowUsesExchange(row: Record<string, unknown>): boolean {\n  if (isExchangeFlag(row['source_is_exchange']) || isExchangeFlag(row['deposit_is_exchange'])) return true\n  if (!Array.isArray(row['path_nodes'])) return false\n  return row['path_nodes'].some(rowNodeIsExchange)\n}\n\nfunction htmlEscape(value: unknown): string {\n  return String(value ?? '')\n    .replaceAll('&', '&amp;')\n    .replaceAll('<', '&lt;')\n    .replaceAll('>', '&gt;')\n    .replaceAll('\"', '&quot;')\n    .replaceAll(\"'\", '&#39;')\n}\n\nexport async function traceDepositSources(\n  remoteClient: Client,\n  _config: Pick<InvestigatorConfig, 'dataDir' | 'serverPort'>,\n  options: TraceDepositSourcesOptions,\n): Promise<TraceToolResult> {\n  const network = options.network.trim()\n  const depositInputs = parseAddressList(options.depositAddresses)\n  if (!network) throw new Error('network is required')\n  if (depositInputs.length < 1) throw new Error('deposit_addresses must contain at least 1 address')\n  if (depositInputs.length > 5) throw new Error('deposit_addresses cannot exceed 5 addresses')\n  const topologyScope = options.topologyScope ?? DEFAULT_TOPOLOGY_SCOPE\n  const resolvedDeposits = await resolveIdentityKeys(remoteClient, network, depositInputs, topologyScope)\n  const unresolvedDeposits = depositInputs.filter((input) => !resolvedDeposits.has(input))\n  const deposits = [...new Set(depositInputs.filter((input) => resolvedDeposits.has(input)).map((input) => resolvedDeposits.get(input)!))]\n  const preferredByIdentity = new Map(depositInputs.filter((input) => resolvedDeposits.has(input)).map((input) => [resolvedDeposits.get(input)!, input] as [string, string]))\n  const maxHops = clampInt(options.maxHops, 2, 1, 5)\n  const minAmountSum = Math.max(0, options.minAmountSum ?? 0)\n  const window = traceActivityWindow(undefined, options.timeRange)\n\n  const batch = deposits.length > 0\n    ? await callGraphBatch(\n        remoteClient,\n        network,\n        Array.from({ length: maxHops }, (_, index) => reverseDepositSourceQueryAtDepth(deposits, index + 1, minAmountSum, window, topologyScope)),\n        topologyScope,\n      )\n    : { facts: { queries: [] } }\n  const failures: QueryFailure[] = []\n  const rows: Array<Record<string, unknown>> = optionalResultsWithPrefix(batch, 'reverse_deposit_sources_', failures)\n    .filter((row) => !reverseDepositSourceRowUsesExchange(row))\n    .map((row, index) => ({\n      ...row,\n      path_id: `p${index + 1}`,\n    }))\n  const truncationWarnings = (batch.facts?.queries ?? [])\n    .filter((entry) => entry.id?.startsWith('reverse_deposit_sources_') && (entry.results?.length ?? 0) >= REVERSE_DEPOSIT_SOURCES_LIMIT)\n    .map((entry) => `${entry.id} hit the ${REVERSE_DEPOSIT_SOURCES_LIMIT}-row limit; results may be truncated.`)\n  const addresses = new Map<string, {\n    address: string\n    roles: Set<TraceRole>\n    labels: string[]\n    is_exchange?: boolean\n    confidence: 'low' | 'medium' | 'high'\n    rationale: string[]\n  }>()\n  for (const deposit of deposits) addTraceAddress(addresses, deposit, 'seed_deposit', 'Deposit/cashout seed provided by caller')\n\n  const edges: Array<Record<string, unknown>> = []\n  const paths: Array<Record<string, unknown>> = []\n  for (const row of rows) {\n    const sourceAddress = typeof row['source_address'] === 'string' ? row['source_address'] : ''\n    const depositAddress = typeof row['deposit_address'] === 'string' ? row['deposit_address'] : ''\n    const pathAddresses = stringArrayValue(row['addresses']) ?? [sourceAddress, depositAddress].filter(Boolean)\n    addTraceAddress(addresses, sourceAddress, 'candidate_suspect', 'Upstream address funds a suspected deposit/cashout seed')\n    addTraceAddress(addresses, depositAddress, 'seed_deposit', 'Deposit/cashout seed provided by caller')\n    const edgeProps = Array.isArray(row['edge_props']) ? row['edge_props'] as Array<Record<string, unknown>> : []\n    const edgeIds: string[] = []\n    for (let index = 0; index < pathAddresses.length - 1; index += 1) {\n      const props = edgeProps[index] ?? {}\n      const edgeId = `e${edges.length + 1}`\n      edgeIds.push(edgeId)\n      edges.push({\n        edge_id: edgeId,\n        from_address: pathAddresses[index],\n        to_address: pathAddresses[index + 1],\n        edge_type: 'FLOWS_TO',\n        amount_usd_sum: numberValue(props['amount_usd_sum']) ?? numberValue(row['amount_usd_sum']),\n        tx_count: numberValue(props['tx_count']) ?? numberValue(row['tx_count']),\n        first_seen_timestamp: numberValue(props['first_seen_timestamp']) ?? numberValue(row['first_seen_timestamp']),\n        last_seen_timestamp: numberValue(props['last_seen_timestamp']) ?? numberValue(row['last_seen_timestamp']),\n        first_tx_id: typeof props['first_tx_id'] === 'string' ? props['first_tx_id'] : typeof row['first_tx_id'] === 'string' ? row['first_tx_id'] : undefined,\n        last_tx_id: typeof props['last_tx_id'] === 'string' ? props['last_tx_id'] : typeof row['last_tx_id'] === 'string' ? row['last_tx_id'] : undefined,\n      })\n    }\n    paths.push({\n      path_id: row['path_id'],\n      direction: 'reverse',\n      source: depositAddress,\n      target: sourceAddress,\n      addresses: [...pathAddresses].reverse(),\n      edge_ids: [...edgeIds].reverse(),\n      hops: numberValue(row['hop']) ?? Math.max(pathAddresses.length - 1, 0),\n      terminal_role: 'source',\n      amount_usd_sum: numberValue(row['amount_usd_sum']),\n      first_seen_ms: numberValue(row['first_seen_timestamp']),\n      last_seen_ms: numberValue(row['last_seen_timestamp']),\n    })\n  }\n\n  const sourceToPathIds = new Map<string, string[]>()\n  const sourceToDeposits = new Map<string, Set<string>>()\n  for (const row of rows) {\n    const source = typeof row['source_address'] === 'string' ? row['source_address'] : ''\n    const deposit = typeof row['deposit_address'] === 'string' ? row['deposit_address'] : ''\n    if (!source) continue\n    sourceToPathIds.set(source, [...(sourceToPathIds.get(source) ?? []), String(row['path_id'])])\n    if (!sourceToDeposits.has(source)) sourceToDeposits.set(source, new Set())\n    if (deposit) sourceToDeposits.get(source)!.add(deposit)\n  }\n  const convergence = [...sourceToPathIds.entries()]\n    .filter(([address]) => (sourceToDeposits.get(address)?.size ?? 0) > 1)\n    .map(([address, pathIds]) => ({\n      address,\n      role: 'candidate_suspect',\n      path_ids: pathIds,\n      reason: 'Same upstream source funds multiple provided deposit/cashout seeds.',\n    }))\n  const candidateSuspects = convergence.map((entry) => entry.address)\n  const candidateLabels = [...sourceToPathIds.keys()].map((address) => ({\n    address,\n    candidate_label: 'candidate_suspect',\n    confidence: candidateSuspects.includes(address) ? 'high' : 'medium',\n    evidence_path_ids: sourceToPathIds.get(address) ?? [],\n    reason: candidateSuspects.includes(address)\n      ? 'Upstream source converges into multiple provided deposit/cashout seeds.'\n      : 'Upstream source funds a provided deposit/cashout seed.',\n    promote_to_core_label: false,\n  }))\n  const graphData = normalizeGraphPayload({\n    schema: 'chain-insights.graph.v1',\n    nodes: [...addresses.values()].map((entry) => ({\n      id: entry.address,\n      address: entry.address,\n      node_type: 'address',\n      roles: [...entry.roles],\n      labels: entry.labels,\n    })),\n    edges: edges.map((edge) => ({\n      source: edge['from_address'],\n      target: edge['to_address'],\n      edge_type: 'flows_to',\n      amount_usd_sum: edge['amount_usd_sum'],\n      tx_count: edge['tx_count'],\n      first_tx_id: edge['first_tx_id'],\n      last_tx_id: edge['last_tx_id'],\n      direction: 'traceback',\n    })),\n    flows: edges.map((edge, index) => ({\n      hop: index + 1,\n      src: edge['from_address'],\n      dst: edge['to_address'],\n      amount_usd_sum: edge['amount_usd_sum'] ?? 0,\n      terminal_exchange: false,\n    })),\n    edge_anchors: [],\n    metadata: {\n      network,\n      deposit_addresses: deposits,\n      generated_at: new Date().toISOString(),\n    },\n  })\n  const archiveHint = await archiveRetryHint(remoteClient, network, topologyScope, edges.length === 0)\n  const summaryText = [\n    `Trace deposit sources complete for ${network}`,\n    ...(unresolvedDeposits.length > 0 ? [`Unresolved (no matching Identity/Address): ${unresolvedDeposits.join(', ')}`] : []),\n    '',\n    `Deposit seeds: ${deposits.join(', ') || 'none resolved'}`,\n    `Reverse path(s): ${paths.length}`,\n    `Shared upstream convergence: ${convergence.length}`,\n  ].join('\\n')\n  const result = {\n    summaryText,\n    structuredContent: {\n      schema: 'chain-insights.trace.v1',\n      tool: 'aml_trace_deposit_sources',\n      network,\n      input: {\n        addresses: deposits,\n        seed_role: 'deposit',\n        ...(options.timeRange ? { time_range: options.timeRange } : {}),\n        ...(minAmountSum > 0 ? { min_amount_sum: minAmountSum } : {}),\n        time_filter: window\n          ? { from_ms: window.fromMs, ...(window.toMs !== undefined ? { to_ms: window.toMs } : {}) }\n          : 'none',\n        max_hops: maxHops,\n        topology_scope: topologyScope,\n      },\n      summary: {\n        seed_count: deposits.length,\n        unresolved_count: unresolvedDeposits.length,\n        path_count: paths.length,\n        edge_count: edges.length,\n        candidate_suspect_count: sourceToPathIds.size,\n        candidate_intermediate_count: 0,\n        candidate_deposit_count: deposits.length,\n        exchange_count: 0,\n      },\n      unresolved: unresolvedDeposits,\n      addresses: [...addresses.values()].map((entry) => ({\n        address: entry.address,\n        roles: [...entry.roles],\n        confidence: entry.confidence,\n        rationale: entry.rationale,\n      })),\n      edges,\n      paths,\n      convergence,\n      exchange_exposure: [],\n      candidate_labels: candidateLabels,\n      artifacts: statelessArtifacts(),\n      evidence: failures.length > 0 ? [{ evidence_type: 'query_summary', summary: `partial query failures: ${failures.length}` }] : [],\n      continuation: {\n        candidate_deposit_addresses: deposits,\n        candidate_suspect_addresses: candidateSuspects,\n        candidate_victim_addresses: [],\n        recommended_next_tools: candidateSuspects.length > 0\n          ? ['aml_trace_suspect_funds', 'aml_address_risk']\n          : ['aml_address_risk', 'graph_query_batch'],\n      },\n      warnings: [\n        ...(paths.length === 0 ? ['No upstream sources were connected in the queried topology.'] : []),\n        ...(unresolvedDeposits.length > 0 ? [`${unresolvedDeposits.length} input address(es) did not resolve to a known Identity and were not traced: ${unresolvedDeposits.join(', ')}.`] : []),\n        ...truncationWarnings,\n        ...archiveHint,\n      ],\n    },\n    graphData,\n  }\n  return publicizeTraceResult(remoteClient, network, result, preferredByIdentity, options.writeArtifacts !== false, topologyScope)\n}\n\nexport async function trackFunds(\n  remoteClient: Client,\n  config: Pick<InvestigatorConfig, 'dataDir' | 'serverPort'>,\n  options: TrackFundsOptions,\n): Promise<{\n  summaryText: string\n  structuredContent: Record<string, unknown>\n  graphData: Record<string, unknown>\n}> {\n  const network = options.network.trim()\n  const trustedInputs = parseAddressList(options.trustedAddresses)\n  const untrustedInputs = parseAddressList(options.untrustedAddresses)\n  if (!network) throw new Error('network is required')\n  if (trustedInputs.length < 1) throw new Error('trusted_addresses must contain at least 1 address')\n  if (trustedInputs.length > 5) throw new Error('trusted_addresses cannot exceed 5 addresses')\n  if (untrustedInputs.length > 5) throw new Error('untrusted_addresses cannot exceed 5 addresses')\n  const resolvedTrackInputs = await resolveIdentityKeys(remoteClient, network, [...trustedInputs, ...untrustedInputs])\n  const trusted = [...new Set(trustedInputs.map((input) => resolvedTrackInputs.get(input) ?? input))]\n  const untrusted = [...new Set(untrustedInputs.map((input) => resolvedTrackInputs.get(input) ?? input))]\n  const overlap = trusted.filter((address) => untrusted.includes(address))\n  if (overlap.length > 0) throw new Error(`Address(es) appear in both trusted and untrusted lists: ${overlap.join(', ')}`)\n\n  const runs: Array<{ role: 'trusted' | 'untrusted'; address: string; result: TraceFundsResult }> = []\n  for (const address of trusted) {\n    runs.push({\n      role: 'trusted',\n      address,\n      result: await runFundFlowProbe(remoteClient, config, {\n        seedAddress: address,\n        network,\n        maxHops: options.maxHops,\n        perAddressLimit: options.perAddressLimit,\n        minAmountSum: options.minAmountSum,\n      }),\n    })\n  }\n  for (const address of untrusted) {\n    runs.push({\n      role: 'untrusted',\n      address,\n      result: await runFundFlowProbe(remoteClient, config, {\n        seedAddress: address,\n        network,\n        maxHops: options.maxHops,\n        perAddressLimit: options.perAddressLimit,\n        minAmountSum: options.minAmountSum,\n      }),\n    })\n  }\n\n  const graphData = normalizeGraphPayload({\n    schema: 'chain-insights.graph.v1',\n    nodes: runs.flatMap((run) => Array.isArray(run.result.graphData.nodes) ? run.result.graphData.nodes : []),\n    edges: runs.flatMap((run) => Array.isArray(run.result.graphData.edges) ? run.result.graphData.edges : []),\n    flows: runs.flatMap((run) => Array.isArray(run.result.graphData.flows) ? run.result.graphData.flows : []),\n    deposits: runs.flatMap((run) => graphArray(run.result.graphData, 'deposits').map((item) => ({ ...item, run_role: run.role, run_address: run.address }))),\n    source_matches: runs.flatMap((run) => graphArray(run.result.graphData, 'source_matches').map((item) => ({ ...item, run_role: run.role, run_address: run.address }))),\n    reverse_leads: runs.flatMap((run) => graphArray(run.result.graphData, 'reverse_leads').map((item) => ({ ...item, run_role: run.role, run_address: run.address }))),\n    edge_anchors: [],\n    metadata: { network, trusted_addresses: trusted, untrusted_addresses: untrusted, generated_at: new Date().toISOString() },\n  })\n\n  return {\n    summaryText: [\n      `Track funds complete for ${network}`,\n      '',\n      `Trusted addresses: ${trusted.join(', ')}`,\n      `Untrusted addresses: ${untrusted.join(', ') || 'none'}`,\n      '',\n      ...runs.map((run) => `## ${run.role}: ${run.address}\\n${run.result.summaryText}`),\n    ].join('\\n'),\n    structuredContent: {\n      schema: 'chain-insights.result.v1',\n      tool: 'track_funds',\n      facts: {\n        network,\n        trusted_addresses: trusted,\n        untrusted_addresses: untrusted,\n        runs: runs.map((run) => ({\n          role: run.role,\n          address: run.address,\n          files: run.result.files,\n          continuation: run.result.continuation,\n          address_map: run.result.addressMap,\n        })),\n      },\n    },\n    graphData,\n  }\n}\n"],"mappings":"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"}