import { SYSTEM_BASE, bloqueContexto, mensajePaso1, mensajePaso2, mensajePaso3 } from "@/lib/propuesta/prompts"; import type { DatosEconomicos } from "@/lib/propuesta/economia"; import type { Hechos, Diagnostico } from "@/lib/propuesta/schemas"; let fallas = 0; function check(n: string, ok: boolean, d = "") { console.log(`${ok ? " OK " : " FALLA"} | ${n}${d ? " -> " + d : ""}`); if (!ok) fallas++; } // ── La capa 1 tiene que ser 100% estable o el cache no sirve de nada ── check("no contiene el anio actual", !SYSTEM_BASE.includes(String(new Date().getFullYear()))); check("no contiene una fecha ISO", !/\d{4}-\d{2}-\d{2}/.test(SYSTEM_BASE)); check("no contiene un numero de cotizacion", !/UJ\d{4}/.test(SYSTEM_BASE)); check("supera el minimo cacheable de 512 tokens", SYSTEM_BASE.length > 2500, `${SYSTEM_BASE.length} chars`); // ── Los diez principios y el semaforo estan presentes ── for (const p of ["P1.", "P2.", "P3.", "P4.", "P5.", "P6.", "P7.", "P8."]) { check(`declara el principio ${p}`, SYSTEM_BASE.includes(p)); } check("explica el semaforo completo", ["rojo:", "ambar:", "azul:", "verde:"].every((c) => SYSTEM_BASE.includes(c))); check("justifica por que el verde importa", SYSTEM_BASE.includes("entre pares")); // ── Reglas de marca ── check("nombra Bucefalo", SYSTEM_BASE.includes("Bucefalo")); check("prohibe otros CRM", SYSTEM_BASE.includes("ningun otro CRM")); check("prohibe USD", SYSTEM_BASE.includes("USD")); check("prohibe garantizar resultados", SYSTEM_BASE.includes("garantizado")); check("prohibe lenguaje corporativo vacio", SYSTEM_BASE.includes("sinergias")); check("restringe a servicios digitales", SYSTEM_BASE.includes("UNICAMENTE servicios digitales")); check("prohibe datos de empleados", SYSTEM_BASE.includes("nombres de empleados")); check("cubre el caso de material pobre", SYSTEM_BASE.includes("MATERIAL ES POBRE")); check("dice que un hueco declarado es contenido de valor", SYSTEM_BASE.includes("contenido de valor")); // ── El contexto degrada con gracia ── const sinNada = bloqueContexto({ transcripcion: "", notas: "", observaciones: "", cliente: "Ana", empresa: "", proyecto: "P" }); check("sin transcripcion lo declara explicitamente", sinNada.includes("No se entrego transcripcion")); check("sin empresa no imprime parentesis vacios", !sinNada.includes("()")); const conTodo = bloqueContexto({ transcripcion: "TRANS", notas: "NOTAS", observaciones: "OBS", cliente: "Ana", empresa: "ACME", proyecto: "P" }); check("incluye la transcripcion", conTodo.includes("TRANS")); check("incluye las notas por partida", conTodo.includes("NOTAS")); check("incluye las observaciones", conTodo.includes("OBS")); check("incluye la empresa entre parentesis", conTodo.includes("(ACME)")); // ── Los tres mensajes piden su herramienta y no filtran dinero ── const econ: DatosEconomicos = { partidas: [{ refPartida: "P01", servicioCotizadoId: "cuid-secreto-abc123", nombre: "Sitio web", fase: 1, tipoPago: "unico", precio: 12345, tiempoEntrega: "2 semanas", modeloCobro: "fijo", horas: null, tarifaHora: null, entregables: [] }], totales: { subtotalUnico: 12345, subtotalMensual: 0, ivaUnico: 1975.2, ivaMensual: 0, totalUnico: 14320.2, totalMensual: 0, totalPrimerAnio: 14320.2, incluyeIva: true }, moneda: "MXN", }; const ctx = { transcripcion: "t", notas: "", observaciones: "", cliente: "Ana", empresa: "ACME", proyecto: "P" }; const hechos = { citas: [], hechos: [], materialesPendientes: [], decisionesPendientes: [], mencionesFueraDeAlcance: [], redFlags: [] } as Hechos; const diag = { hallazgos: [], valorProblema: { dimensiones: [], notaMetodologia: "" }, resultados: [] } as unknown as Diagnostico; const m1 = mensajePaso1(ctx); const m2 = mensajePaso2(ctx, hechos, econ); const m3 = mensajePaso3(ctx, hechos, diag, econ); check("paso 1 pide registrar_hechos", m1.includes("registrar_hechos")); check("paso 2 pide registrar_diagnostico", m2.includes("registrar_diagnostico")); check("paso 3 pide registrar_propuesta", m3.includes("registrar_propuesta")); check("paso 1 exige citas textuales", m1.includes("TEXTUALES")); // P1 estructural: el precio y el cuid NO pueden aparecer en ningun prompt. for (const [nombre, msg] of [["paso 2", m2], ["paso 3", m3]] as const) { check(`${nombre} NO filtra el precio de la partida`, !msg.includes("12345")); check(`${nombre} NO filtra el total`, !msg.includes("14320")); check(`${nombre} NO filtra el cuid real`, !msg.includes("cuid-secreto-abc123")); check(`${nombre} SI incluye la refPartida`, msg.includes("P01")); } console.log(fallas === 0 ? "\ntodo paso\n" : `\n${fallas} fallas\n`); process.exit(fallas === 0 ? 0 : 1);