Primera fase del plugin de propuesta consultiva (docs/superpowers/specs/
2026-07-28-propuesta-consultiva-ia-fase0-fase1-design.md). Recupera el contexto
humano que hoy se captura y se descarta, y cierra los bloqueadores que el
analisis previo destapo.
Seguridad (lo mas urgente):
- POST /mcp no tenia NINGUNA autenticacion: cero Depends() en main.py, mientras
el servicio recibe dominio publico en produccion (SERVICE_FQDN_API_8000).
Cualquiera en internet podia leer y escribir cotizaciones. Ahora exige
require_auth, que ya existia en app/auth.py y no se estaba usando ahi.
- _obtener_cotizacion hacia SELECT c.* y devolvia dict(cot) al agente, asi que
cualquier columna nueva se publicaba sola. Ahora usa lista blanca espejo de
CotizacionResponse, excluyendo observacionesInternas.
Totales:
- Nueva calcularTotalesCotizacion() en calculators.ts como fuente de verdad
unica. El calculo estaba duplicado a mano en siete consumidores.
- conIva() sustituye a los `* 1.16` hardcodeados de pdf-generator y
excel-builder, que ignoraban IVA_RATE y el flag incluirIva.
Contexto humano:
- Campo nuevo Cotizacion.observacionesInternas. La migracion es PURAMENTE
ADITIVA: no mueve ni una fila. El movimiento de datos no hace falta porque la
unica fila de produccion con observaciones ya contiene texto dirigido al
cliente, y separarlo en dos despliegues mantiene el rollback limpio.
- Dos textareas visualmente inconfundibles en el formulario.
- observaciones se imprime por primera vez en el PDF y el Excel; el dato ya
viajaba hasta las rutas de borrador y se tiraba.
- observacionesInternas solo se ve en la app. La garantia es estructural: el
campo no existe en CotizacionPDFData ni en ExcelData, asi que el generador no
puede filtrarlo aunque alguien lo intente.
Bugs vecinos:
- orderBy explicito en las cuatro rutas de export: el PDF asume las partidas
agrupadas por fase y sin orderBy podia diferir del Excel del mismo envio.
- El PDF de borrador leia solo el branding, no los datos bancarios, e imprimia
los hardcodeados del generador.
- detalleModelo local en PDF y Excel omitia la rama "demanda": esa partida
salia en $0 y sin explicacion. Ahora delegan en la version canonica.
- Los bonos salen de la tabla Bono; la lista hardcodeada queda de respaldo y su
texto ya no coincidia con el seed.
- La palomita de los bonos mide 0pt en las fuentes base de PDFKit (verificado),
o sea que salia como dos espacios. Sustituida por una vineta.
Ademas: zod pasa a ser dependencia declarada. Se importaba en schemas.ts y
resolvia transitivamente, asi que un npm ci --omit=dev reventaba.
Verificado con build, lint y 22 comprobaciones funcionales sobre PDF y Excel
reales (texto del cliente presente, texto interno ausente incluso inyectandolo
a la fuerza, texto largo multipagina, y totales con y sin IVA).
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>