Tests y Resolución de Problemas del Asesor de IA
🧪 Tests y Resolución de Problemas del Asesor de IA
Sección titulada «🧪 Tests y Resolución de Problemas del Asesor de IA»🧪 Estrategia de Testing
Sección titulada «🧪 Estrategia de Testing»Ejecuta los comandos con la versión de Node fijada en engines del package.json raíz (>=24.16.0); un Node por defecto más antiguo rompe node:sqlite y el hook de Husky. Ejecuta el typecheck de cada paquete tocado además de los tests: vitest ha permanecido en verde mientras tsc y vue-tsc detectaban errores reales. Ver Desarrollo y Tests.
# Todo el repositorio (Turborepo, concurrencia 1)pnpm typecheck && pnpm test
# Por paquetepnpm --filter @criptofolio/backend typecheck && pnpm --filter @criptofolio/backend testpnpm --filter @criptofolio/frontend typecheck && pnpm --filter @criptofolio/frontend testpnpm --filter @criptofolio/shared-types testpnpm --filter @criptofolio/core-domain testpnpm --filter @criptofolio/database test
# Un solo archivo de specpnpm --filter @criptofolio/backend exec vitest run src/core/infrastructure/ai/__tests__/mastraChunk.spec.tsEl script typecheck del frontend es vue-tsc --build --force; un --noEmit a secas sobre este tsconfig de estilo solución no comprueba ningún archivo.
| Spec (relativo al paquete) | Demuestra |
|---|---|
shared-types/tests/schemas/advisor-stream.spec.ts |
Esquemas de frames, unión failed estricta, ausencia de transport-lost. |
shared-types/tests/schemas/advisor-model-chain.spec.ts |
Formas de entrada local frente a medida, regla del sufijo cloud, classifyExecutionProfile. |
shared-types/tests/schemas/advisor-local-budgets.spec.ts |
Fórmulas de presupuesto local, valores por defecto, techos. |
core-domain/src/__tests__/{holdingRanking,displayOrdering,downsampleSeries}.spec.ts |
Helpers solo de visualización, comparación basada en Money. |
database/tests/integration/migration_009_*.spec.ts, migration_010_*.spec.ts |
Forma de la tabla, restricciones, perfil anulable. |
backend/.../domain/__tests__/advisor-domain-isolation.spec.ts, models/__tests__/advisor-event.spec.ts |
El dominio no importa nada externo; unión de eventos. |
backend/.../use-cases/__tests__/AskAdvisorUC.spec.ts |
Resolución de contexto, persistencia del recibo en cada evento terminal, fila abortada. |
backend/.../adapters/__tests__/SqliteAdvisorRunLogAdapter.spec.ts |
Upsert, columnas NULL, motivo de rechazo nunca escrito. |
backend/.../ai/__tests__/MastraAdvisorAdapter.spec.ts, mastraChunk.spec.ts, classifyProviderError.spec.ts |
Mapeo chunk-a-evento, recibos, clasificación de fallos, saneado. |
backend/.../ai/__tests__/mastraImportZone.spec.ts, noTelemetry.spec.ts |
Zona de importación de @mastra/*; sin dependencia de telemetría. |
backend/.../ai/models/__tests__/* |
Filtrado de credenciales, resolución de cadena, derivación de perfil, presupuestos. |
backend/.../ai/tools/__tests__/* |
Proyección y presupuesto de cada herramienta; toolSurface.spec.ts (25 herramientas, recuento por nivel de 14 core y 11 extended, exposición exacta por perfil de ejecución, solo lectura, envoltorios finos); noModelAccountId.spec.ts; enforceBudget.spec.ts. |
backend/.../ai/guardrails/__tests__/*, agents/__tests__/* |
Fundamento, descargo, topología, delegación en dos llamadas, filtrado de llamadas a herramienta. |
backend/.../routes/__tests__/advisor.test.ts, advisorMounting.spec.ts, advisorRollback.spec.ts, app-type.spec-d.ts, credentials.test.ts |
Contratos HTTP y 400, exactamente seis rutas, rollback sin cadena, tipado de AppType, proveedores de IA en el registro de la bóveda. |
backend/.../di/__tests__/*, dtos/__tests__/advisor.spec.ts |
Composición perezosa, capacidad de liberación, mapeo a red. |
frontend/.../adapters/__tests__/RestAdvisorAdapter.*.spec.ts |
Parseo SSE (CRLF, chunks partidos), frames inválidos, llamadas de configuración. |
frontend/.../composables/__tests__/useAdvisorChat.spec.ts, useAdvisorQueries.spec.ts |
Máquina de estados, reglas de reintento, aborto, manejo de hilos. |
frontend/.../components/advisor/__tests__/* |
Carcasa del panel, estados, herramientas, descargo, pasos, chip de rechazo, seguridad del markdown, tokens de diseño. |
frontend/.../Settings/components/advisor/__tests__/* |
Editor de cadena, límites, presupuestos derivados, cableado. |
Según las reglas del proyecto, un comportamiento nuevo requiere primero un test que falle y una rotura deliberada que confirme que la aserción prevista se pone en rojo. El tasks.md del cambio registra esas comprobaciones de rotura.
🩺 Resolución de Problemas y FAQ
Sección titulada «🩺 Resolución de Problemas y FAQ»El panel dice “No model available”. ai_advisor_model_chain no está definido o es inválido, o todas las entradas se filtraron con la bóveda desbloqueada. Añade una entrada en Ajustes → Asesor de IA. Sin cadena configurada, ambas rutas de ask responden NO_MODEL_AVAILABLE y nada más en la aplicación cambia.
El panel dice que la bóveda está bloqueada. Se omitieron todas las entradas con clave porque la bóveda está bloqueada; desbloquéala en Ajustes → Bóveda. Un reinicio del backend (incluidas las recargas de tsx watch en desarrollo) la vuelve a bloquear. Una cadena que contiene una entrada ollama local sigue respondiendo mientras está bloqueada.
“No provider answered” con un proveedor nombrado. Lee cause.kind: auth-rejected significa que la clave fue rechazada (usa una clave API creada en la cuenta del proveedor); model-not-found significa que el id de modelo es incorrecto para ese proveedor; rate-limited, provider-unavailable y network son temporales y ofrecen Reintentar. El log del servidor tiene un aviso por ejecución fallida con el estado HTTP.
Un modelo local responde mal o trunca. Revisa el contextWindow declarado. Los presupuestos escalan con él (15 por ciento por herramienta, 60 por ciento por ejecución). Una ventana mayor de lo que el modelo soporta realmente produce prompts sobredimensionados; una mucho menor produce resultados truncated frecuentes.
Un modelo de Ollama con sufijo cloud aparece etiquetado como “cloud” aunque uso el daemon local. Correcto: el daemon lo reenvía a ollama.com, así que los datos salen de la máquina. Usa un modelo sin sufijo para operar solo en local.
Las respuestas muestran una insignia “Cifras incompletas”. Una herramienta informó tipos de cambio o precios ausentes (ratesIncomplete o pricesIncomplete). Corrige los datos subyacentes en lugar del prompt.
Una respuesta fue rechazada. O bien el texto coincidió con el patrón de evasión fiscal (siempre se rechaza), intentó anular el descargo, o hizo una afirmación de inversión sin actividad de herramientas en el turno. Reformula usando tus propios datos; el chip lo sugiere.
¿Puede el asesor filtrar por cuenta? Sí, por nombre, mediante account_holdings. El modelo pasa el nombre de una cuenta, nunca un id (un modelo que envíe accountId sigue fallando con INVALID_TOOL_INPUT). El servidor busca primero una coincidencia exacta sin distinguir mayúsculas y solo prueba un prefijo si ningún nombre coincide exactamente. Un prefijo compartido por varias cuentas devuelve ambiguous con los nombres candidatos, y un nombre desconocido devuelve not_found con los nombres de las cuentas de nivel superior; al agente se le indica que pregunte cuál querías decir. El resultado es una sección por cuenta del árbol de la cuenta encontrada y nunca suma entre cuentas.
Una ejecución local no ofrece las herramientas extendidas. Es por diseño: un perfil de ejecución local expone solo las 14 herramientas core, porque los modelos locales pequeños eligen peor con una lista larga. Usa una cadena metered o mixta para tener las 25. Ver Catálogo de Herramientas.
account_holdings responde ambiguous o not_found. Indica un nombre de cuenta más largo o exacto. No se adivinó ni se sumó nada.
Una herramienta de escenarios responde “no poseído”, “sin valorar” o “coste base no convertible”. Son resultados reales, no errores: not_held, unvalued, empty_portfolio (scenario_position_value, scenario_portfolio_shock), unconvertible_cost_basis y zero_quantity (breakeven_price). El agente debe expresarlos tal cual y nunca estimar una cifra sustituta; corrige los datos de precio, tipo de cambio o coste base subyacentes.
performance_history muestra puntos con valor nulo. Un punto sin tipo de cambio en su fecha o antes llega con portfolioValue: null, nunca un valor en EUR ni 0.
Una herramienta nueva responde truncated. Su presupuesto metered por herramienta es demasiado pequeño para ese payload. Súbelo en Ajustes, o acota la petición (por ejemplo, un rango de fechas más corto en tx_search). Los perfiles almacenados antes de que existiera la herramienta usan el presupuesto por defecto. Ver Proveedores y Modelos.
¿Sale algo de mi máquina? Solo la llamada al modelo. Ver Auditoría y Privacidad.
¿Cómo borro las conversaciones? Detén el backend y elimina ai-advisor.db y sus archivos -wal, -shm o -journal. La tabla de auditoría no se ve afectada y no contiene contenido.
Una ejecución aparece como aborted en la tabla de auditoría. El cliente se desconectó o pulsó Stop antes de un evento terminal. Esa fila no tiene proveedor, tokens ni pasos por diseño.
Los perfiles de ejecución almacenados rompen el asesor con INTERNAL_ERROR. Consulta la advertencia en API y Streaming.
🚧 Divergencias Conocidas
Sección titulada «🚧 Divergencias Conocidas»Lugares donde el código publicado difiere del diseño OpenSpec, o va más allá.
| Tema | El diseño dice | El código hace |
|---|---|---|
| Sufijo de modelo cloud | D16 clasifica una entrada ollama como nube cuando el id de modelo termina en :cloud. |
isOllamaCloudModelId también trata -cloud (por ejemplo gpt-oss:120b-cloud) como nube, y readModelChain descarta un contextWindow obsoleto de esas entradas almacenadas. |
Migración 010 |
Relaja una restricción. | Implementada como DROP TABLE más recreación, destruyendo las filas de auditoría existentes. Segura solo bajo la suposición documentada de pizarra limpia. |
| Ajuste de perfil de ejecución corrupto | La cadena degrada con elegancia. | El ajuste de perfil no tiene una protección equivalente; un valor incorrecto produce HTTP 500 o INTERNAL_ERROR. |
| Tarea 16.7 | Commit local. | Sin marcar en el momento de la auditoría; está marcada en el cambio archivado, que ya está fusionado en openspec/specs/. |
| Orden de transacciones spot | La búsqueda de transacciones spot ordena de la más reciente a la más antigua. | Las páginas de tx_search van de la más reciente a la más antigua con desempate por id_hash. La rama all que usa GET /tax/transactions/spot conserva el orden del libro (la más antigua primero, por ORDER BY t.timestamp ASC en SQLiteLedgerAdapter), de modo que la respuesta de esa ruta no cambia. |
Verificado como coherente con el diseño: los veinticinco nombres de herramientas en ADVISOR_TOOL_NAMES, los seis ids de proveedor, el conjunto de columnas de 009/010, los campos del frame done, las claves de ajustes y la ausencia en el código de las claves de previsión.