Skip to content

WL Aqua Intelligence v4 — fórmulas de scoring y KPIs

Referencia de todos los valores calculados que el sistema deriva del archivo WL_Aqua_Intelligence_v4_data_actualizada.xlsx (Winston Loaiza, analizado el 2026-08-03): semáforos por criterio, índice de salud, prioridad, recomendación, los KPIs del dashboard ejecutivo, el FCA por talla y el ranking de prioridades.

Es la evolución de la sábana ya documentada en Sábana de cálculos —mismas fórmulas de producción— más una capa nueva de scoring sobre un consolidado de 47 lagunas / 4 fincas. 9 hojas: Portada, Consolidado, 4 hojas por finca, Parámetros KPI, Dashboard, Prioridades.

Esta página es la fuente única de las fórmulas. Los *-flow.md de 09 · Dashboard, 10 · Parámetros KPI y 11 · Prioridades documentan contrato, RBAC y flujo de cliente, y enlazan acá en vez de repetir las fórmulas.

Procedencia y nivel de confianza

Distinguir de dónde sale cada regla importa: la primera lectura del xlsx se hizo con data_only=True (solo valores calculados) y llevó a inferir mal la regla de prioridad. Releído con data_only=False aparecieron las fórmulas reales.

OrigenQué cubreConfianza
Celdas AB2:AI2 del xlsx (data_only=False)Los 5 semáforos, índice de salud, prioridadFórmula literal del socio
Hoja Parámetros KPI del xlsxTramos, cortes y penalizaciones por defectoValores literales
Reconstrucción validada 47/47Recomendación (única columna sin fórmula)Regla reconstruida, no enunciada por el socio
Decisión propia documentada en ADRTrato de "sin dato", FCA por talla, agregados del dashboardDecisión de implementación

Verificación: las fórmulas se recalcularon sobre las 47 filas reales del archivo y coinciden 47/47 (kpi-scoring.spec.ts, fixture __fixtures__/wl-aqua-v4-consolidado.ts).

El .xlsx no vive en este repo: es un artefacto de planificación, en _planning/_referencia/ del monorepo.

Insumos: de dónde sale cada dato

Todo el scoring corre sobre la fila que ya arma la sábana semanal — no hay captura de campo nueva ni tablas propias. Estos son los insumos y su origen real (ReportesService.buildRow), a una fecha de corte reportDate:

InsumoOrigen (Prisma)Selección
hectaresPool.hectares
sowingDateSiembra.date, o Cycle.startDate si no hay siembradel ciclo vigente al corte
larvaeCountSiembra.larvaeCount
initialWeightGSiembra.initialWeightG
pesoActGSampling.avgWeightGel muestreo más reciente con date ≤ reportDate
pesoAntGSampling.avgWeightGel más reciente con date ≤ inicio de semana
pesoHace3SemanasGSampling.avgWeightGel más reciente con date ≤ reportDate − 21 d
survivalPctPopulation.survivalPctla última evaluación con date ≤ reportDate (sobrevivencia real, la del aguaje)
raleoLbHarvest.poundssuma de type = 'raleo' y status = 'ejecutado' con date ≤ reportDate
feedAccumKgFeeding.kgsuma con date ≤ inicio de semana
feedWeekKgFeeding.kgsuma con inicio de semana < date ≤ reportDate
factorFeedingCurvePoint.factorcurva del ciclo (Cycle.feedingCurve) o la default de la organización, buscada por pesoActG

Los derivados intermedios que consume el scoring (fcr, crecimientoDiaG, crecimiento3SemanasG, lbPorHaTotal) se calculan en computeWeeklyRow — sus fórmulas están en Sábana de cálculos.

Los 5 criterios

Orden canónico (el de las columnas AB:AF): FCA → supervivencia → crecimiento diario → crecimiento 3 semanas → carga.

CriterioValor que evalúaDirecciónTramos
fcafcr de la filamenor es mejorpor peso (4)
supervivenciasurvivalPct (real, del aguaje)mayor es mejorpor peso (5)
crecimientoDiariocrecimientoDiaGmayor es mejorplano
crecimiento3Semanascrecimiento3SemanasGmayor es mejorplano
cargalbPorHaTotal (incluye raleo)menor es mejorplano

La dirección no es configurable: es semántica del dominio, no un umbral. Dejarla en BD permitiría invertir el significado de un criterio editando una fila.

Carga usa lb/ha total, no el actual — verificado contra las 8 lagunas del xlsx con raleo ≠ 0. Mide presión acumulada de producción por hectárea (incluyendo lo ya sacado en raleos), no biomasa en pie. Es contraintuitivo, pero es lo que hace el archivo del socio.

Los criterios planos se modelan como un solo tramo con maxWeightG = 9999 (UNBOUNDED_BRACKET_WEIGHT_G), para que el motor recorra los 5 criterios con el mismo código.

Cómo se resuelve el estado

El tramo vigente es el de menor maxWeightG que no supere pesoActG (los IF anidados del Excel); si el peso es null o excede todos, cae en el último.

menor es mejor (fca, carga)
  valor ≤ greenCut                    → verde
  valor ≤ yellowCut                   → amarillo
  redCut = null                       → rojo
  valor ≤ redCut                      → rojo   ·  si no → critico

mayor es mejor (supervivencia, crecimientos)
  valor ≥ greenCut                    → verde
  valor ≥ yellowCut                   → amarillo
  en otro caso                        → rojo

Solo FCA define redCut, así que es el único criterio que alcanza critico; los otros cuatro tienen 3 niveles.

Tramos y penalizaciones por defecto

Valores exactos de la hoja Parámetros KPI, sembrados por organización (DEFAULT_KPI_THRESHOLDS). Cada organización los edita desde el admin: se leen siempre de la BD, no son constantes de negocio duras.

FCA (menor es mejor) — penalizaciones 0 / 12 / 25 / 35:

PesoVerde ≤Amarillo ≤Rojo ≤Crítico
≤ 10 g11.11.2> 1.2
≤ 15 g1.151.21.2> 1.2
≤ 20 g1.151.251.25> 1.25
> 20 g1.251.51.5> 1.5

Supervivencia % (mayor es mejor) — penalizaciones 0 / 15 / 30 / 30:

PesoVerde ≥Amarillo ≥Rojo
≤ 5 g9285< 85
≤ 10 g8575< 75
≤ 15 g8070< 70
≤ 20 g7565< 65
> 20 g7060< 60

Criterios planos:

CriterioVerdeAmarilloRojoPenalizaciones (V/A/R/C)
Crecimiento diario≥ 0.3 g/día≥ 0.2< 0.20 / 10 / 20 / 20
Crecimiento 3 semanas≥ 2 g≥ 1.6< 1.60 / 8 / 15 / 15
Carga (lb/ha total)≤ 3499≤ 4499> 44990 / 7 / 15 / 15

En los tramos de FCA de ≤ 15 g, ≤ 20 g y > 20 g, yellowCut y redCut son iguales, así que la banda "rojo" queda vacía: esas piscinas pasan de amarillo directo a crítico. Solo el tramo ≤ 10 g produce rojo. Es consecuencia literal de los valores de la hoja del socio, no un ajuste nuestro — está anotado en el backlog para confirmárselo.

"Sin dato"

Si el insumo es null, el criterio marca sin_dato y penaliza 0, en los cinco criterios.

⚠️ Es una diferencia deliberada con la hoja del socio: allí solo FCA y crecimiento 3 semanas tienen rama "Sin dato"; en supervivencia, crecimiento diario y carga un dato en blanco hace fallar la comparación y cae en Rojo, penalizando a una piscina por falta de datos. Ver ADR-0057.

Además, un 0 en crecimiento 3 semanas también es "sin dato" (KPI_ZERO_IS_MISSING). Viene de la fórmula del socio (AE) y tiene sentido de dominio: sin un muestreo distinto 21 días atrás, ambos pesos resuelven al mismo muestreo y la resta da 0 — eso significa "no hay ventana de 3 semanas", no "el camarón no creció".

Índice de salud

Celda AG:

indiceSalud = MAX(0, 100 − Σ penalización(estado) de los 5 criterios)

Las penalizaciones salen de la configuración de cada criterio (tabla de arriba), editables por organización. sin_dato siempre penaliza 0.

Prioridad

Celda AH. No es función pura del índice: combina el índice con el conteo de semáforos. Una piscina con índice 78 puede ser "Alta" por tener un solo Rojo.

Urgente  si índice < urgenteIndexBelow  O  (Rojos + Críticos) ≥ urgenteRedCount
Alta     si índice < altaIndexBelow     O  (Rojos + Críticos) ≥ altaRedCount
Media    si índice < mediaIndexBelow    O  Amarillos ≥ mediaYellowCount
Normal   en cualquier otro caso

Los 6 números son parte del KpiThresholdSet, editables desde el admin. Default del Excel v4: 60 / 3 / 75 / 1 / 90 / 2.

Recomendación

Celda AI — la única columna KPI sin fórmula en el xlsx (texto plano en las 47 filas). La regla se reconstruyó por inspección y reproduce 47/47: una frase fija por criterio en estado no-verde, en el orden canónico de columnas, unidas por ; , con la primera letra capitalizada y punto final.

CriterioAmarilloRojo / Crítico
FCAvigilar fcarevisar conversión y ración
Supervivenciavigilar supervivenciaauditar mortalidad
Crecimiento diarioajustar estrategia de alimentocorregir crecimiento
Crecimiento 3 semanas(sin frase)revisar tendencia de 3 semanas
Cargavigilar cargaevaluar carga y aireación

Sin ningún criterio en alerta: "Mantener manejo y seguimiento semanal."

⚠️ Dos cosas no confirmadas por el socio: el tope de 3 frases se ejercita en una sola de las 47 filas (n = 1, laguna N7L05) — es la explicación más simple que reproduce ese texto, no una regla que él haya enunciado; y en crecimiento 3 semanas el amarillo no aporta frase porque en su hoja solo el rojo la genera. El catálogo es una constante editable en código (KPI_RECOMENDACION_FRASES), no vive en BD.

Dashboard ejecutivo (hoja Dashboard)

Agregados sobre las filas por piscina (computeDashboardKpis). Regla transversal: los promedios y conteos de scoring toman solo piscinas con ciclo — una piscina vacía evalúa sus 5 criterios en sin_dato y siempre da índice 100, así que incluirla inflaría el promedio.

ValorFórmulaSobre qué filas
haTotalΣ hectarestodas
biomasaLbΣ biomasaLbtodas
lbPorHaActualbiomasaLb / haTotaltodas
lbPorHaTotal(biomasaLb + Σ raleoLb) / haTotaltodas
survivalPctΣ(survivalPct × larvaeCount) ÷ Σ larvaeCountponderado por cantidad sembradacon ciclo, con ambos datos
survivalEstimadaPctmisma ponderación, como fuente independientecon ciclo, con ambos datos
fcr(Σ feedAccumTotalKg × 2.2046) ÷ (biomasaLb + Σ raleoLb)todas
crecimientoDiaGpromedio simplecon ciclo
promedioIncrementosGpromedio simplecon ciclo
densidadHaΣ larvaeCount ÷ Σ hectares de las filas con siembracon larvaeCount
indiceSaludPromediopromedio simple del índicecon ciclo
prioridadCountsconteo por nivelcon ciclo
atencionPrioritariaCounturgente + altacon ciclo

El FCA consolidado es alimento total ÷ biomasa total, no un promedio de los FCA por piscina ni una ponderación — confirmado por Winston el 2026-08-04, coincide con lo ya implementado. La sobrevivencia sí se pondera por cantidad sembrada: un promedio simple de porcentajes sobre-pesaría a las piscinas chicas.

El denominador de densidadHa son las filas con larvaeCount, no "todas las que tienen ciclo": hoy coincide, porque todo ciclo se crea junto con su siembra, pero así el KPI no se diluye si alguna vez existe un ciclo activo sin siembra.

Resumen por sector

Por sector: hectares y biomasaLb (sumas), fcr (misma fórmula del consolidado aplicada solo a sus filas), indiceSaludPromedio y atencionPrioritariaCount (solo filas con ciclo).

Top-5 piscinas

Las limit (default 5) piscinas de peor índice de salud, solo entre las que tienen ciclo. Desempate determinista: prioridad más severa primero, luego código de piscina.

FCA por talla

Alcance pedido por Winston el 2026-08-04, no está en el Excel v4. Agrupa las piscinas por el tramo vigente del criterio fca de la organización —el mismo que ya define su semáforo, vía findBracket: no hay tabla de tallas propia— y aplica dentro de cada grupo la misma fórmula del FCA consolidado.

Diferencia con el scoring: ahí un pesoActG nulo cae en el último tramo (un semáforo necesita algún valor); acá las filas sin peso van a un grupo Sin dato propio, para no inflar ni desinflar el último tramo con piscinas que no se pudieron tallar.

📌 Los grupos quedan acoplados a los umbrales de FCA: si un admin edita esos tramos, los grupos de talla cambian con ellos. Es el comportamiento buscado (ADR-0059), pero conviene confirmarlo con Winston la primera vez que use la pantalla.

Prioridades (hoja Prioridades)

Ranking operativo: las mismas filas por piscina, ordenadas por índice de salud ascendente (peor primero). No agrega tablas ni queries: reutiliza el mismo fetch y el mismo buildRow que la sábana y el dashboard. Entran solo piscinas con ciclo, por la misma razón que en los agregados.

Dónde vive cada cálculo

Archivo (camaroneras_backend/src/modules/)Qué calcula
reportes/kpi-scoring.tssemáforos, índice de salud, prioridad, recomendación
reportes/kpi-thresholds.defaults.tsvalores de la hoja Parámetros KPI (seed)
reportes/weekly-report.calc.tsderivados de la fila (fcr, crecimientos, lbPorHaTotal…)
reportes/weekly-report.aggregate.tsselección histórica de pesos e incrementos
reportes/dashboard.calc.tsagregados, resumen por sector, top-5, FCA por talla
reportes/reportes.service.tsbuildRow: ata los insumos a Prisma; getWeekly / getDashboard / getPriorities

Consumidores: GET /reports/weekly (reportes:ver), GET /reports/dashboard y GET /reports/priorities (ambos dashboard:ver), y el CRUD de umbrales GET/PATCH /kpi-thresholds (parametros-kpi:ver / editar).

Decisiones de negocio que fijan estas fórmulas

Confirmadas con Winston Loaiza (2026-08-03 / 04):

  • Finca = Sector. El Excel consolida 4 fincas; acá son 4 sectores de la organización.
  • La biomasa y el FCA usan la sobrevivencia REAL (prueba de campo / aguaje); la estimada es proyección. ⚠️ No dijo explícitamente cuál alimenta la biomasa: se asume la real, que es lo que el sistema ya hacía y lo coherente con su distinción.
  • El FCA consolidado es alimento total ÷ biomasa total, no ponderado por biomasa.
  • El número de ciclo se cuenta por laguna y un ciclo pertenece al año en que se sembró — ver ADR-0058.

Pendientes de confirmar

  • El catálogo definitivo de frases de la recomendación, incluido el tope de 3 (n = 1).
  • Que la banda "rojo" vacía en 3 de los 4 tramos de FCA sea intencional.
  • Que el acoplamiento talla ↔ umbrales de FCA sea el comportamiento esperado en uso real.