CreaRack-SL

El cron supercontext de OPS fallaba por un lote de bib_index_chunks que superaba el techo de bge-m3

Cuándo

Fallando en producción desde el 21-09-2026; diagnosticado y corregido en dos pasos el 22-09-2026 (s339): fc4f0033 (11:13, PR #179) y c62ec19a (11:24, PR #180).

Síntomas visibles

El cron supercontext de OPS, que reindexa la wiki en la Biblioteca, fallaba con "Max context reached 63700 tokens but model supports only 60000". El ingestor mandaba lotes fijos de 25 chunks a bib_index_chunks, y uno de ellos (lote 36 de 1.043 chunks, posiciones 876-900) reventaba siempre el mismo techo del modelo de embeddings bge-m3.

Causa raíz

Dos capas de causa, cada una diagnosticada y corregida por separado:

  1. Diagnóstico inicial (PR #179): el troceado limita cada chunk a ~400 palabras, pero el markdown denso del Supercontexto (tablas con identificadores, rutas, código) llega a ~6 tokens por palabra — así que 25 chunks “pequeños” pueden sumar más de los 60.000 tokens que admite bge-m3 por lote. El primer fix estimó el coste del lote como la SUMA de tokens de sus chunks y cerró el lote a partir de un presupuesto de 40.000 tokens estimados (dos tercios del techo, para absorber error de estimación).
  2. El primer fix no bastó: en OPS, con el payload real, el mismo lote 36 seguía fallando con los mismos 63.700 tokens. Medido a mano: la suma de texto del lote eran solo ~17.000 tokens, muy por debajo del presupuesto de 40.000 — pero contenía un párrafo de NEXT.md de 7.602 caracteres (~2.548 tokens), y 2.548 × 25 = 63.700 exactos. La causa real: Workers AI rellena (“pads”) cada texto del lote hasta la longitud del más largo antes de mandarlo al modelo, así que el coste real es tokens(chunk más largo) × nº de chunks del lote, no la suma. La estimación por suma del primer fix nunca habría partido ese lote.

Fix aplicado

  • fc4f0033 (PR #179): crea el módulo compartido scripts/_lib/chunk_batches.mjs con splitChunkBatches(), que cierra el lote por presupuesto de tokens ESTIMADOS (suma) o al llegar a 25 chunks. Insuficiente por sí solo (ver causa raíz punto 2).
  • c62ec19a (PR #180): corrige splitChunkBatches() para cerrar el lote cuando el coste RELLENADO (max(tokens) × (n+1)) superaría el presupuesto — nueva función paddedBatchTokens(). Simulado contra el corpus real del Supercontexto (1.043 chunks): 42 lotes, coste rellenado máximo 39.729 — dentro del presupuesto de 40.000. Test nuevo con el lote real que rompió el 21-09; 7 tests en total, todos verdes.

Ambos umbrales (CHARS_PER_TOKEN = 2.5, BATCH_TOKEN_BUDGET = 40000) quedan marcados UNVERIFIED en el código: elegidos por criterio conservador, no medidos contra el tokenizador real de bge-m3.

Lecciones

Cuando un proveedor rellena (“pads”) un lote de entradas hasta la más larga, el coste que cobra no es la suma de las partes — es el máximo multiplicado por el número de partes. Una estimación por suma puede parecer conservadora y aun así fallar exactamente en el caso que importa: un lote con una entrada mucho más larga que el resto. El primer arreglo se validó por criterio (la suma parecía razonable); el segundo se validó midiendo el payload real que rompía en OPS.

Preventivos futuros

test/chunk-batches.test.ts (7 casos) incluye el lote real del 21-09-2026 como caso de regresión. Verificación del efecto pendiente de confirmar en producción: relanzar el cron supercontext en OPS tras el merge y comprobar chunks_updated > 0 sin error — no confirmado en el momento de este registro. Pendiente aparte, de calidad y no de fallo: el troceado no parte un párrafo de una sola línea de 1.200 palabras (el primero de NEXT.md); bge-m3 lo admite (8k tokens) pero es un chunk pobre para retrieval.

Véase también

  • [[entity—biblioteca—service—bib-ingest-claude-method]]
  • [[entity—biblioteca—handler—bib-index-chunks]]
  • [[entity—biblioteca—tool—bib-pipeline-stats]]
  • [[concept—workspace—incidents-index]]
  • [[incident—20260506—bib-reindex-subrequest-limit]]