CreaRack-SL

Oráculo — Deduplicación de chips de sources por path único

Resumen

El componente SearchInline del Oráculo mostraba múltiples chips de source cuando el backend recuperaba varios chunks del mismo archivo. Edu reportó que “todos los chips abren README.md” — visualmente parecía links rotos porque 4-5 chips tenían títulos distintos (Claude Method · Componentes (1/2), Claude Method · Principios…) pero todos navegaban al mismo documento.

La causa raíz no era un bug de backend: el retrieval RAG funciona correctamente enviando 5 secciones del README al modelo para contexto. El problema era puramente de presentación en UI.

Solución implementada

Nueva función dedupeSources(sources: OracleSource[]) añadida en SearchInline.tsx (sesión s73):

function dedupeSources(sources: OracleSource[]): Array<{
  title: string;
  path: string | null;
  href: string | null;
  count: number;
}> {
  const byKey = new Map<string, { title: string; path: string | null; href: string | null; count: number }>();
  for (const s of sources) {
    const key = s.path || s.title;           // agrupa por path; fallback a title
    const existing = byKey.get(key);
    if (existing) { existing.count++; continue; }
    const cleanTitle = s.title.split(' · ')[0].trim() || s.title; // quita sufijo " · <sección>"
    byKey.set(key, { title: cleanTitle, path: s.path, href: sourceToHref(s.path), count: 1 });
  }
  return Array.from(byKey.values());
}

Comportamiento antes/después

AntesDespués
[Claude Method · Componentes (1/2)][Claude Method (5 secciones)]
[Claude Method · Componentes](fusionado)
[Claude Method · Principios](fusionado)
[Claude Method · Quick Start](fusionado)
[Claude Method · Quick Start](fusionado)

Cuando count === 1, el label es el título limpio sin sufijo. Cuando count > 1, se añade (N secciones).

Alcance del cambio

  • Solo frontend — src/components/shell/SearchInline.tsx.
  • Sin cambios en el backend, la API /api/ask, ni el pipeline de retrieval.
  • Los chunks siguen enviándose íntegros al modelo LLM (contexto completo preservado).
  • La deduplicación es únicamente visual, en el render de los chips.

Lógica de agrupación

La clave de agrupación es s.path || s.title:

  • Con path: se usa el path relativo del archivo como clave canónica. Chunks del mismo archivo siempre colapsan.
  • Sin path (sources sin archivo asociado): se usa el title completo como fallback, lo que evita fusiones falsas entre documentos de distinta procedencia.

El title limpio se extrae tomando solo la parte anterior al separador ·, que es la convención usada en el backend para componer títulos de chunks (<doc_title> · <heading>).

Contexto histórico

  • Reportado por Edu en sesión s73.
  • El retrieval RAG siendo correcto no implica que la UI deba exponer cada chunk; los usuarios esperan ver documentos, no fragmentos internos.
  • Patrón similar al que usan sistemas como Perplexity: agregar citations por dominio/documento, no por chunk.

Véase también

  • [[feature—workspace—oraculo-el]]
  • [[incident—20260519—oraculo-hardening-v1]]
  • [[entity—workspace—endpoint—oraculo-ask]]