Sobre la Aplicación

WHeat-Jobs | Fenotipo

1. Identificación de la obra y declaración de autoría

La presente memoria técnica describe la arquitectura, organización funcional y modelo operativo del sistema software WHeat-Jobs | Fenotipo, desarrollado como aplicación web para la integración, estructuración y explotación funcional de datos biométricos y clínicos.

Se hace constar que Ricardo Manuel Trigo Calonge es autor del diseño funcional del sistema, de su arquitectura de software, de la organización de módulos, de la lógica algorítmica y del código fuente principal incorporado a la presente obra.

2. Objeto y finalidad funcional del sistema

El sistema WHeat-Jobs | Fenotipo está orientado a la integración y análisis funcional de datos biométricos diarios, analíticas clínicas y variables personales, con el objetivo de generar indicadores compuestos y evaluar tendencias temporales.

El sistema no se limita al almacenamiento de datos, sino que incorpora mecanismos propios de formación de contexto fisiológico, cálculo técnico, persistencia histórica y evaluación funcional.

3. Arquitectura general del sistema

Patrón arquitectónico Modelo Vista Controlador (MVC)
Lenguaje principal C# · .NET 10 · ASP.NET Core MVC
Persistencia SQL Server mediante Entity Framework Core
Autenticación ASP.NET Core Identity
Motores de cálculo Motor hardcoded, motor declarativo y modo dual comparativo
Asistencia IA Ollama Cloud (por defecto) / Claude API (alternativo) · Modelo: gemma4:31b · Procesamiento asíncrono en background con cola de canal interno
Importación masiva Subida ZIP fragmentada por bloques, recomposición en servidor, extracción de export.xml y generación de reducidos semanales
Importación analítica clínica Lectura automática de informes de laboratorio en PDF mediante IA nativa (AnthropicClient / documento directo, sin OCR previo): extracción de hasta 60 biomarcadores, conversión automática de unidades según laboratorio, revisión con semáforo de rangos de referencia y persistencia en AnaliticaClinica

4. Modelo de datos

PerfilPersonal

Contiene los datos estructurales del usuario, incluyendo edad, altura, sexo y otros elementos necesarios para la interpretación funcional.

BiodataDiaria

Registro diario estructurado que contiene información biométrica agregada y normalizada procedente de fuentes internas o externas.

AnaliticaClinica

Almacena biomarcadores clínicos utilizados como soporte del cálculo funcional. Dispone de CRUD completo e importación automática desde PDF: la IA extrae hasta 60 parámetros (hematología, lípidos, enzimas, tiroides, orina…) con conversión automática de unidades y revisión asistida antes de persistir.

HealthScoreHistory

Persistencia técnica del resultado de cálculo con su contexto temporal.

EnergyDailyBalance

Persistencia diaria del balance energético: ingesta, gasto basal y activo ajustados, macronutrientes, alcohol, proteína/kg y clasificación oficial del estado energético.

HealthEvolutionSnapshot

Persistencia del resultado heurístico vigente: objetivo, alineación de pauta, decisión operativa y justificación funcional.

IntakePool / IntakePoolItem / IntakePoolFoodItem

Gestión semanal de ingesta alimentaria por usuario: 7 slots diarios con sus alimentos, gramos confirmados y JSON nutricional calculado por IA u OpenFoodFacts. Multiusuario — cada usuario dispone de su propio pool aislado.

UserEnergyCalibration

Factor de corrección de ingesta calórica derivado empíricamente por regresión MCO para cada usuario. Incluye factores de corrección de gasto basal y activo importado de HealthKit. El factor de ingesta se aplica solo sobre macros; el alcohol usa fórmula determinista y queda excluido de la corrección.

MetabolicAdaptationSnapshot

Snapshot de adaptación metabólica calculada sobre una ventana temporal configurable (14–90 días). Persiste el gap entre TDEE teórico por el modelo energético y TDEE real estimado por balance de masa, con nivel de adaptación (Sin / Leve / Moderada / Severa), delta de peso, R² de regresión de peso, cobertura proteica media y alertas de reactivación metabólica y proteína. Soporta serie histórica de 12 ventanas de 28 días. Generación automática nocturna mediante MetabolicSnapshotWorker, que cada noche recalcula D-1 y D-2 para absorber datos del wearable completados o corregidos al día siguiente.

5. Secuencia funcional del algoritmo

  1. Importación masiva — recepción del ZIP, recomposición por bloques, extracción del export.xml y persistencia interna.
  2. Importación de analítica clínica desde PDF — subida del informe de laboratorio; la IA extrae hasta 60 biomarcadores con conversión automática de unidades, el usuario revisa en pantalla con semáforo de rangos y confirma la persistencia en AnaliticaClinica.
  3. Reducción semanal y agregación diaria — generación de XML reducidos por semana y transformación a registros normalizados de BiodataDiaria.
  4. Cálculo energético diario — a partir de BiodataDiaria, generación y persistencia de EnergyDailyBalance con balance, macronutrientes y estado energético.
  5. Construcción de la Colección de Datos Funcionales — selección de analítica válida y ventana biométrica; formación del HealthDashDataBundle.
  6. Ejecución del motor activo — cálculo de Score SNC, Metabólico y Bioenergético mediante motor seleccionado.
  7. Persistencia del resultado — registro en HealthScoreHistory con contexto temporal y técnico completo.
  8. Evaluación heurística — contraste con objetivo, dirección, alineación de pauta y decisión operativa. Persistencia en HealthEvolutionSnapshot.

6. Integración de asistencia inteligente mediante modelos IA

El sistema incorpora módulos de asistencia funcional basados en modelos de lenguaje. El proveedor por defecto es Ollama Cloud, con Claude API como alternativa conmutable desde la consola de administración. El modelo activo se configura mediante OllamaCloud:Model (actualmente: gemma4:31b).

Los módulos IA activos son:

  • Análisis nutricional de ingesta — dos modos: IA (estimación de macros y energía por modelo de lenguaje) y modo híbrido OFf+IA (datos reales de etiqueta desde OpenFoodFacts para productos envasados de marca; IA como fallback para genéricos y platos caseros; bebidas alcohólicas siempre a IA por cálculo determinista). Antes de llamar a cualquiera de los dos motores, cada alimento se contrasta contra una biblioteca personal por usuario (nombre normalizado, composición por 100g/ml); si ya está guardado, se reutiliza sin volver a estimar — elimina la variabilidad de recalcular el mismo alimento cada vez.
  • Aviso de alérgenos en la estimación nutricional — capa desacoplada del cálculo de macros (un primer intento de incrustarla en el mismo prompt de cálculo desestabilizó el resultado numérico y se revirtió). Combina un diccionario determinista de los 14 alérgenos de declaración obligatoria de la UE, con normalización de texto y detección de negaciones ("sin gluten", "deslactosado"...) para evitar falsos positivos por coincidencia de subcadena, con una capa complementaria de IA cuyo resultado se filtra por el mismo diccionario antes de fusionarse — el diccionario actúa como veto final ante la falta de determinismo observada en la IA. Se aplica igual en ambos motores de cálculo de ingesta.
  • Automatización de Ingesta — generación sintética de una semana de registros de ingesta a partir del historial del usuario (requiere ≥ 30 días previos). Calcula media (μ) y desviación típica (σ) por macro y día de semana; genera valores mediante muestreo normal con σ efectiva ≤ 25 % de μ. Se recomienda su uso solo como último recurso ante ausencia de datos reales, ya que introduce inexactitud estadística en los registros de ingesta. Mejor que no tener datos, pero nunca equivalente a la declaración real.
  • Asistente IA conversacional — chatbot contextual accesible desde cualquier página mediante botón flotante. Recibe los últimos 30 días de BiodataDiaria (energía basal, activa, ingesta, balance, macros, sueño, FC, HRV…) y el perfil personal como contexto. Compatible con Claude API y Ollama. Historial en cliente (10 turnos), sin tablas nuevas.
  • Resumen interpretativo de evolución de BiodataDiaria.
  • Análisis integrado de HealthDash — síntesis en lenguaje natural del estado fisiológico global, sin carácter diagnóstico.
  • Interpretación de dinámica metabólica.
  • Extracción automática de analítica clínica desde PDF — el informe de laboratorio se procesa directamente por la IA como documento nativo (sin OCR previo), mapeando hasta 60 biomarcadores al modelo AnaliticaClinica con corrección automática de escalas (notación científica ×10ⁿ, PCR mg/dL→mg/L, Urea mmol/L→mg/dL, T4 pmol/L→ng/dL, Calcio/Fósforo mmol/L→mg/dL).
  • Revisión histórica parcial con resumen IA — informe longitudinal para un período seleccionado por el usuario, que integra perfil fenotípico, evolución de scores SNC/MET/BIOE, balance energético (ingesta/basal/NEAT/total/balance), macronutrientes medios y analítica clínica con verificación sistemática de rangos de referencia sobre ~55 parámetros (BuildParametros); genera un resumen interpretativo asíncrono de cinco párrafos estructurados mediante plantilla versionada en BD (HistoriaPacientePromptSeeder), con informe imprimible como PDF desde el navegador.
  • Evolución longitudinal de parámetros clínico-analíticos — módulo de análisis de series temporales de analíticas clínicas en el intervalo que el usuario seleccione (presets de 6 meses, 1, 2 y 5 años o rango libre). Muestra ocho gráficas por categoría fisiológica (lipídico, glucémico, renal, hepático, tiroides, inflamación, micronutrientes, hematología). Una matriz comparativa interactiva presenta todos los biomarcadores disponibles en una tabla única con las fechas como columnas y el delta (Δ) entre primera y última analítica con color semántico por parámetro. Un análisis IA asíncrono — generado mediante plantilla versionada ANALITICA_EVOLUCION — interpreta las tendencias sostenidas, identifica cambios clínicamente relevantes y agrupa los hallazgos por sistema, tomando siempre al propio paciente como referencia en el tiempo, sin baremos poblacionales externos.
  • Inspector de asuntos internos IA — registro de diagnóstico de cada llamada a Ollama/Claude (proveedor, origen, usuario, modelo, motivo de parada, tokens, duración), persistido fuera del árbol público de la aplicación y accesible solo para el rol Admin, para diagnosticar lentitud o fallos intermitentes con datos objetivos en vez de suposición.
  • Análisis de impacto etílico — modelo MCO que cuantifica el efecto del alcohol sobre el peso: coeficiente de la mañana siguiente D+1 (β_alc), de dos mañanas después D+2 (β_lag) e índice fisiológico HRV/sueño (β_sleep), con error estándar y p-valor de cada uno. Separado de la regresión, calcula el equivalente calórico teórico del alcohol (7 kcal/g) y lo contrasta con una predicción de balance energético independiente (sin usar el peso observado) para detectar, sin circularidad, desviaciones que en series largas puedan indicar compromiso hepático.
  • Generación de documentos RGPD y contratos — producción asistida por IA de consentimientos informados, políticas de privacidad y contratos profesional-paciente adaptados al perfil del profesional y del paciente.
  • Todas las llamadas a IA se procesan en segundo plano mediante AiBackgroundWorker y IBackgroundTaskQueue, desacoplando la solicitud del usuario de la espera bloqueante y mostrando estimación de tiempo dinámica en la interfaz.

    7. Subsistema de importación de Biodata desde wearables

    El sistema dispone de dos vías de importación masiva de BiodataDiaria desde dispositivos wearable, accesibles desde el menú Adquisición de datos → Apple / Android (ZIP) mediante un selector de plataforma iOS/Android:

    7.1 Apple HealthKit (iOS)

    Procesa la exportación estándar de la app Salud de iPhone (export.zip), transformando el export.xml en registros diarios normalizados.

    1. Recepción del export.zip en bloques (chunked upload).
    2. Recomposición y extracción del export.xml interno.
    3. Generación de XML reducido semanal con filtro temporal inteligente.
    4. Agregación diaria por tipo de registro (pasos, FC, HRV, sueño, peso…).
    5. Previsualización por semana y persistencia selectiva en BiodataDiaria.
    7.2 Android / Google Health Connect vía heredada

    Procesa el ZIP de Google Takeout generado con Google Fit y/o Health Connect. Compatible con cualquier reloj integrado en Health Connect (Samsung Galaxy Watch, Pixel Watch, Fitbit, Garmin…). Marcada como obsoleta en la interfaz desde julio de 2026 en favor del webhook automatizado (7.4): el HRV que produce es un valor ya agregado por fila del export, sin el filtrado por ventana de sueño real que sí aplican las demás vías.

    1. Recepción del ZIP de Takeout en bloques (misma mecánica chunked que iOS).
    2. Parseo en memoria de dos formatos: CSVs de Daily activity metrics (Google Fit, un fichero por día) y CSVs por tipo de métrica en carpetas Health Connect.
    3. Acumulación por fecha con upsert diferido: el primer valor encontrado por campo tiene prioridad; los formatos se complementan sin sobreescribirse.
    4. Previsualización con tabla de días (verde = nuevo, amarillo = actualiza existente) antes de confirmar.
    5. Confirmación: upsert real en BiodataDiaria. HRV mapeado como HrvSource.HealthKitSDNN (algoritmo SDNN, propio de los ficheros HeartRateVariabilitySdnn de Health Connect); FC media como FcMediaSource.HealthKitDiaria.
    6. Limpieza automática del ZIP temporal en servidor tras la importación.
    7.3 Apple HealthKit — JSON manual y automatización REST desatendida

    Canal alternativo al XML (7.1), basado en el esquema JSON de la app de terceros Health Auto Export, con dos modos: subida manual de fichero y un endpoint REST (POST /api/healthautoexport/{token}) que recibe datos directamente desde una automatización del dispositivo, sin sesión interactiva.

    1. Autenticación por token opaco (GUID) en PerfilPersonal, generado/regenerado por el usuario.
    2. Mismo motor de agregación Suma/Promedio/Último que el pipeline XML, vía acumulador por (fecha, campo).
    3. Deduplicación por preferencia de fuente (reloj sobre teléfono) en pasos, distancia, pisos y energía, evitando doble cómputo cuando ambos dispositivos registran la misma actividad.
    4. Reconstrucción del valor bruto de ejercicio cuando métricas y entrenamientos llegan en llamadas REST separadas, para que el resultado converja sin importar el orden de llegada.
    5. Marca de trazabilidad (FechaUltimaActualizacion / OrigenUltimaActualizacion) en cada fila tocada, visible en el listado de Biodata y en el panel de adherencia del inicio.
    7.4 Android — Webhook desatendido ("Health Connect Webhook")

    Canal equivalente a 7.3 pero para Android: un endpoint REST (POST /api/healthconnectwebhook/{token}) que recibe datos directamente desde la app de terceros "Health Connect Webhook" (proyecto "HC Webhook", código abierto), instalada en el propio dispositivo, sin sesión interactiva ni exportación manual.

    1. Reutiliza el mismo token opaco (GUID) que iOS en PerfilPersonal.HealthAutoExportToken — identifica al usuario, no la plataforma.
    2. La app lee Health Connect vía su API nativa y publica un JSON plano con un array por tipo de dato; el sueño llega ya como sesiones con desglose de fases (sin reconstrucción por huecos, a diferencia del XML de Apple).
    3. Reutiliza sin cambios el mismo motor de persistencia que el JSON de iOS (7.3): mismo DTO por día, mismas reglas de Suma/Promedio/Último.
    4. El HRV se recoge como muestras crudas por instante y se filtra por la ventana de sueño real de esa noche (mismo criterio que 7.1/7.3), marcado con HrvSource.HealthConnectRMSSD (RMSSD, como Oura, pero origen distinto).
    5. Implementado en julio de 2026; pendiente de verificación end-to-end contra un dispositivo Android real.

    7.2 Motor estructural de agregación diaria

    El sistema incorpora un motor estructural capaz de procesar documentos XML complejos mediante lectura secuencial en streaming.

    Este motor permite procesar estructuras jerárquicas sin necesidad de cargar el documento completo en memoria, permitiendo el tratamiento eficiente de archivos de gran tamaño.

    Se soportan estructuras complejas como:

    • Record
    • Workout
    • WorkoutStatistics
    • ActivitySummary
    • Correlation

    El sistema incorpora mecanismos para identificar correctamente intervalos temporales que cruzan medianoche.

    8. Elementos de originalidad técnica

    1. Construcción de la Colección de Datos Funcionales (HealthDashDataBundle).
    2. Motores de cálculo intercambiables: hardcoded, declarativo y modo dual comparativo.
    3. Persistencia histórica completa con contexto temporal, analítica y motor utilizado.
    4. Importación masiva estructural mediante subida ZIP fragmentada por bloques.
    5. Motor de agregación diaria estructural con lectura XML en streaming.
    6. Modelo diario de balance energético y disponibilidad funcional (EnergyDailyBalance).
    7. Análisis longitudinal de tendencias sobre variables directas de BiodataDiaria.
    8. Arquitectura de procesamiento IA asíncrono con cola de canal, almacenamiento de resultado y estimación dinámica de tiempos.
    9. Sistema dual de proveedor IA (Ollama / Claude) con consola de administración y conmutación en tiempo de ejecución.
    10. Sistema declarativo de gestión de prompts IA: plantillas versionadas (IaPromptTemplate), bloques de contenido componibles (IaPromptBlock) y motor de construcción con interpolación de variables de contexto (IaPromptBuilderService), administrable sin modificación de código fuente.
    11. Subsistema de importación automática de analíticas clínicas desde PDF mediante IA nativa: envío del documento directamente como base64 a AnthropicClient (sin OCR previo), extracción de hasta 60 biomarcadores, conversión automática de unidades por laboratorio, revisión interactiva con semáforo de rangos de referencia y persistencia estructurada en AnaliticaClinica.
    12. Módulo de revisión histórica parcial: servicio propio (HistoriaPacienteService) que compila un informe longitudinal del período seleccionado integrando perfil, evolución de scores, balance energético, macros y analítica clínica con verificación de rangos de referencia sobre ~55 parámetros; emite un resumen IA asíncrono de cinco párrafos estructurados (estado funcional, balance energético, nutrición/sueño/composición, analítica clínica y recomendaciones) mediante plantilla versionada (HistoriaPacientePromptSeeder), con informe imprimible como PDF desde navegador.
    13. Módulo de evolución longitudinal de parámetros clínico-analíticos (AnaliticaEvolucionAiService): procesa la serie temporal completa de objetos AnaliticaClinica en el intervalo seleccionado; construye ocho gráficas Chart.js por sistema fisiológico y una matriz comparativa interactiva (biomarcadores × fechas) con delta Δ codificado por semántica clínica del parámetro; encola un análisis IA asíncrono (IBackgroundTaskQueue, tipo ANALITICA_EVOLUCION) que interpreta tendencias sostenidas agrupadas por sistema, tomando al propio paciente como referencia, sin baremos poblacionales. Plantilla de prompt versionada en BD y editable desde la consola de prompts sin redesplegar.
    14. Modo híbrido OFf+IA para estimación nutricional: consulta OpenFoodFacts para productos envasados de marca (datos de etiqueta real) con fallback automático a IA para alimentos no encontrados; bebidas alcohólicas siempre calculadas por IA mediante fórmula determinista.
    15. Detección de alérgenos desacoplada del cálculo de macros: capa determinista (diccionario de los 14 alérgenos de declaración obligatoria de la UE, con detección de negaciones textuales del tipo "sin gluten") combinada con una capa complementaria de IA cuyo resultado se filtra por el mismo diccionario antes de fusionarse, evitando que la falta de determinismo observada en la IA introduzca falsos positivos.
    16. Modelo de impacto etílico (AlcoholCalibrationService): regresión MCO con F fijo que estima los coeficientes β_alc (retención la mañana siguiente, D+1), β_lag (efecto diferido dos mañanas después, D+2) y β_sleep (índice fisiológico HRV/sueño), junto con su error estándar y p-valor (inversión de (XᵀX)⁻¹ vía Gauss-Jordan) dado que R² suele ser bajo. El equivalente calórico teórico del alcohol (7 kcal/g) se calcula aparte de la regresión y se contrasta con una predicción de balance energético independiente —construida solo desde ingesta, gasto y alcohol, sin usar el peso observado— para validar la hipótesis sin caer en tautología; la base de la futura alerta de compromiso hepático.
    17. Factor de corrección de ingesta aplicado exclusivamente sobre macros (HC×4 + Prot×4 + Grasa×9); el alcohol queda excluido de la corrección por usar fórmula determinista (ml × graduación × 0,789 × 7).
    18. Sistema de alerta automática de recalibración: en el primer ApplyToBiodata del día y mediante botón manual, comprueba si el balance acumulado implica variación de peso superior al umbral individual (0,5 % del peso actual, rango 200-800 g) y han transcurrido ≥ 28 días desde la última calibración.
    19. Arquitectura multiusuario con tres perfiles: profesional (crea y gestiona pacientes, accede a su propio expediente), paciente (creado por el profesional con credenciales propias) y usuario autónomo. El profesional alterna entre su expediente y el del paciente mediante contexto de sesión con validación de vinculación activa. Módulo de mensajería asíncrona profesional-paciente con tipos Indicación y SolicitudPermiso (aceptable/rechazable por el paciente). Generación asistida por IA de documentos RGPD y contratos profesional-paciente.
    20. Módulo de detección y medición de adaptación metabólica (MetabolicAdaptationService): cuantifica el gap entre TDEE teórico por el modelo energético (EnergyDailyBalance.EnergiaGastoTotalKcal) y TDEE real estimado por balance de masa (TDEE_real = (ΣIngestaCorregida − ΔPeso_kg × 7 700) / n_días), con regresión OLS sobre la serie de peso (umbral R² 0,25) para aislar variación de masa de ruido hídrico. Clasifica la adaptación en cuatro niveles internos (SinAdaptacion / Leve / Moderada / Severa; en pantalla, etiqueta corta — Sin adaptación (o "Muy adaptable" si el residual es negativo) / Leve / Moderada / Severa — con la interpretación completa en el tooltip del badge, unificada entre AdaptacionMetabolica e HistoricoAdaptacion vía NivelAdaptacionDisplay, sin alterar el umbral que decide cada nivel), emite alertas de reactivación metabólica (adaptación > 250 kcal) y de cobertura proteica insuficiente (< 80 %), y ofrece serie histórica de 12 ventanas de 28 días con representación Chart.js. Los snapshots se persisten en MetabolicAdaptationSnapshots. Indicadores complementarios añadidos sobre la misma ventana: TEF individualizado por macronutriente (proteína 25 % / hidratos 8 % / grasa 2 % / alcohol 15 %, puramente informativo, no recalcula TDEE_real), Ratio TDEE real/teórico ("Índice de Rendimiento Metabólico"), ΔAdaptación a 30 días (velocidad de cambio contra el snapshot histórico más cercano) y variabilidad de peso residual (dispersión de los pesajes alrededor de la misma recta Theil-Sen que ya calcula ΔPeso). Ambas pantallas marcan en ámbar las ventanas con R² < 0,50 (mismo umbral en las dos) para señalar cuando el ΔPeso de esa ventana está dominado por ruido ajeno a grasa/masa magra (rachas de alcohol de varios días, sal, ciclo hormonal) — la cifra no cambia, solo su fiabilidad.
    21. Índice de Eficiencia Locomotora (IEL), puramente diagnóstico (nunca calibrador): cociente entre la energía declarada por el wearable y la estimada por un modelo mecánico de la marcha (E = distancia × masa × 0,75 kcal/(kg·km) + pisos × masa × 0,15 kcal/(kg·piso)). Solo importa su tendencia en el tiempo: una deriva decreciente sostenida es la tercera línea de evidencia de adaptación metabólica activa (junto a la brecha TDEE_teórico/TDEE_real y la regresión OLS del peso) — el coste real de caminar baja tras pérdida de peso sostenida (Rosenbaum et al., 2008: −20–25% tras perder el 10% del peso). Se muestra como tarjeta diagnóstica en Adaptación Metabólica; ver el bullet siguiente para por qué ninguna vía indirecta (incluida esta) se usa para fijar el factor de Activa.
    22. Detección de eventos de readaptación — Refeed/Diet break (RefeedDietBreakDetectionService): escaneo retrospectivo y automático (cada noche, vía MetabolicSnapshotWorker) del balance energético diario, clasificando cada día en Déficit / Mantenimiento / Superávit agresivo según una banda ±10 % del TDEE teórico diario. Una Readaptación ligera (Refeed) es una racha de 1-2 días en banda de mantenimiento precedida de ≥5 días consecutivos en déficit; una Readaptación prolongada (Diet break) es una racha de 7-14 días precedida de ≥14 días consecutivos en déficit. Rachas de 3-6 días quedan deliberadamente sin clasificar. Cada evento persistido (RefeedDietBreakEvents) incluye una confirmación informativa (no excluyente) de si el paciente volvió a déficit después, y una marca ImpulsadoPorAlcohol: compara cuánto del salto real de balance (déficit previo → ventana del evento) explican el alcohol y los hidratos por separado, y advierte (sin excluir el evento) cuando el alcohol explica la mayoría del salto y los hidratos no — un refeed real busca reponer glucógeno/leptina vía hidratos, algo que el alcohol no hace. Es 100% retrospectivo: el sistema no distingue si el patrón fue planeado o casual, el efecto medido es el mismo en ambos casos.
    23. Conservación de la Flexibilidad Metabólica (FlexibilidadMetabolicaService): módulo complementario y conceptualmente separado de la Adaptación Metabólica — Adaptación mide si el cuerpo está ahorrando energía (TDEE teórico vs. real); Flexibilidad mide la probabilidad de conservar la capacidad de alternar entre sustratos energéticos, a partir de señales conductuales (no mide el cambio de sustrato directamente, requeriría calorimetría indirecta). Aplica el modelo jerárquico de referencia de Fenotipo: fuerza, cardio (BiodataDiaria.MinutosEjercicioGym/MinutosEjercicioExterior) y variabilidad de peso se comparan contra la propia media del paciente en los 90 días anteriores a la ventana, no contra recomendaciones poblacionales (OMS/ACSM) ni umbrales fijos; si no hay al menos 14 días de histórico previo, el criterio (o la etiqueta, en el caso de variabilidad de peso) se omite en vez de sustituirse por un valor poblacional por defecto. El criterio de déficit prolongado usa la adaptación ya medida por MetabolicAdaptationService (Nivel/residual), no un simple recuento de días — un paciente puede llevar semanas en déficit sin que su TDEE_real se resienta. Un criterio adicional ("Recuperación tras tu última readaptación") compara la adaptación medida antes/después del evento de readaptación más reciente ya concluido con ≥7 días de margen, verificando el efecto real en vez de asumir que el evento ya basta. Presenta un checklist de criterios binarios sin ponderar (enfoque tipo Apgar, puntuación X/Y variable, 3-6 según disponibilidad de datos), un panel de recomendaciones no prescriptivas con prioridad cualitativa (Alto/Medio, apoyada en la evidencia ya citada en Adaptación Metabólica) y una interpretación en lenguaje natural generada por reglas deterministas (sin llamada a IA) a partir de los mismos datos.
    24. Factor de actividad: tres vías indirectas probadas y descartadas, ninguna sustituye al peso real: el factor bibliográfico fijo (0,75, meta-análisis ajeno), la validación por FC (Keytel 2005) y, después, WalkingMetCalibrationService (tramos de marcha reales del usuario contra predicción MET/mecánica, sin sueño ni velocidades >8 km/h) se probaron en ese orden y los tres se retiraron por el mismo motivo de fondo: todos comparan la Energía Activa contra un modelo idealizado o mecánico, no contra el dato objetivo. El último —más riguroso que los dos anteriores en su construcción (deduplicaba Watch+iPhone, excluía sueño, techo biomecánico de velocidad)— tampoco resultó una base fiable para fijar el factor. Conclusión adoptada: ActiveEnergyCorrectionFactor se deja en 1,00 por defecto y solo se ajusta con evidencia directa (calorimetría indirecta real), nunca por un modelo indirecto. Los tres servicios de derivación indirecta se han eliminado del código (no archivados); el IEL se conserva únicamente como señal diagnóstica en Adaptación Metabólica.
    25. Metodología canónica de calibración — 1:1:1 y prueba-error contra peso real: calibrar los tres factores (ingesta, basal, activa) a la vez es circular, porque la ingesta se deriva del gasto total, que ya incluye basal y activa con sus factores aplicados — cambiar cualquiera de los otros dos desplaza mecánicamente la ingesta recomendada sin evidencia nueva sobre ella. El procedimiento adoptado: fijar los tres factores en 1,00 (neutro), recalcular histórico, calibrar solo la ingesta por MCO, aplicar y recalcular de nuevo, y validar el resultado comparando el Δ peso que implica el balance acumulado contra el Δ peso real — idealmente sobre días no usados en la propia calibración, para evitar una coincidencia tautológica. Antes de aceptar Basal=1,00 como neutro conviene contrastar el basal de HealthKit contra Mifflin-St Jeor y Katch-McArdle (con grasa corporal real por bioimpedancia) — comparación que cada usuario debe hacer con sus propios datos, sin generalizar el resultado de otro: en el caso del fundador (un único individuo, no una expectativa universal), las dos fórmulas independientes coincidieron entre sí pero quedaron ~24-29% por debajo de su basal de Apple, señal de que estaba inflado en términos absolutos para él (no solo "un algoritmo distinto pero igualmente válido", como se había concluido antes de este contraste). Corregir su Basal a ~0,77 (el valor que igualaba su basal medio con su referencia Mifflin/Katch-McArdle) redujo su ingesta recomendada de 1,74 a 1,44 y mejoró su validación fuera de muestra de un 18,4% a un 0,33 kg sobre 90 días — mejora real, aunque el residuo no está descompuesto del todo. El paso de validación está automatizado en la app (EnergyWeightValidationService, tarjeta "Validación: peso calculado vs. peso real" en el panel de Calibración) para que cada usuario repita este proceso con sus propios datos, sin depender de scripts SQL manuales ni de las cifras de otro usuario.
    26. Oxigenación nocturna — SDS/SAP como cribado de apnea del sueño: dos índices deliberadamente desacoplados (SleepOxygenationService). El SDS (Índice de Desaturación del Sueño) es puramente objetivo: z-score de la SpO₂ media nocturna (ventana 20:00-11:00) contra el baseline personal, con la dirección invertida respecto al resto de scores del sistema —aquí más alto es peor—, mínimo de 5 lecturas por noche y 7 noches de baseline. El SAP (Probabilidad de Apnea del Sueño) combina 50% SDS con 50% de una puntuación STOP-BANG simplificada de 7 factores (IMC, edad, ronquidos, apnea observada, hipertensión, somnolencia diurna, alcohol), sin pesos diferenciados por factor y con renormalización cuando faltan datos, marcando explícitamente como "cribado incompleto" cuando hay menos de 4 de los 7 disponibles. La SpO₂ intradía no se persiste en base de datos: se lee bajo demanda del export.xml de HealthKit y solo se recalcula cuando el fichero cambia, evitando reprocesar un export de varios cientos de MB en cada visita. Presentado siempre como cribado orientativo, nunca como diagnóstico.
    27. Generador de Informes — exploración dinámica sin persistir diseño ni resultado: herramienta de auto-servicio (InformeDinamicoService) que une BiodataDiaria y EnergyDailyBalance por fecha, permitiendo elegir libremente entre ~40 campos agrupados en 6 temas clínicos (peso, actividad, cardio, sueño, nutrición, energía/balance) y una ventana temporal, sin necesidad de SQL ni desarrollo a medida por cada pregunta puntual. Ni la selección de campos ni el resultado se guardan en base de datos — la propia URL con querystring es la única "persistencia", reproducible o compartible reenviando el enlace. El orden por cualquier campo se resuelve por reflexión sobre un único catálogo, sin switch manual por variable, y el gráfico asigna cada serie a un eje izquierdo o derecho según su magnitud real en los datos del usuario, para que un campo de escala grande (p. ej. pasos) no aplaste visualmente a uno de escala pequeña (p. ej. IMC). El traslado a IA se resuelve copiando el informe en formato tabla al portapapeles en vez de construir una tubería de IA nueva, reutilizando el asistente conversacional ya existente.
    28. Correlación Termogénesis-Recuperación — convergencia entre dos baselines personales: el indicador de Adaptación metabólica arrastra un sesgo estructural (el basal teórico nunca acierta al milímetro el metabolismo real de cada individuo), pero ese sesgo es aproximadamente constante en el tiempo — el metabolismo basal es fisiológicamente estable y cambia despacio, como confirma el seguimiento a largo plazo de "The Biggest Loser" — así que el valor absoluto de Adaptación no es del todo fiable, pero sí su tendencia. CorrelacionTermogenesisService cruza el histórico ya persistido de Adaptación (ventanas de 28 días rodantes) con el de Recovery (diario, HRV/FC reposo/temperatura/sueño), promediando Recovery sobre la misma ventana de cada snapshot de Adaptación — ambos sistemas ya usan el mismo criterio de baseline personal, comparables por construcción sin normalización especial. No calcula ningún índice compuesto: marca convergencia negativa cuando Adaptación y Recovery empeoran a la vez respecto a la ventana anterior, con justificación fisiológica directa (la restricción calórica crónica se asocia a caída de HRV y subida de FC reposo en la literatura de RED-S/infra-alimentación) — dos señales independientes moviéndose juntas es una convergencia real, no una coincidencia estadística de métricas sin relación mecanística entre sí.
    29. Fiabilidad del HRV nocturno en el Panel de Recuperación: cada registro guarda también HrvMuestrasNocturnas (nº de muestras crudas promediadas esa noche dentro de la ventana de sueño), no solo el valor final — con Apple Watch, 2 muestras/noche resultó ser lo normal (80% de 112 noches reales), no una excepción rara. El criterio es asimétrico y ya no descarta ningún valor: con pocas muestras (menos de 3) y un valor anormalmente bajo (por debajo de -1,5σ del baseline propio), si esa noche hubo vigilia nocturna ≥30 min el valor se sustituye por la mediana del baseline personal (HrvSustituido, marcado con asterisco en la vista) solo para este cálculo — el crudo de BiodataDiaria.HrvMs no se toca nunca, así que ningún otro módulo (Biodatos diarios, exports...) hereda la sustitución; si no hubo vigilia que lo explique, el valor se mantiene tal cual, porque un HRV bajo sin vigilia de por medio no es ruido de medición sino señal fisiológica real (estrés, sobreentrenamiento...). Un valor anormalmente alto con pocas muestras se mantiene siempre, porque los artefactos de medición típicos de HRV deprimen el valor, no lo inflan. Verificado con el caso real del 21/07/2026: 12,66 ms (media 26,0/σ7,3 → z=-1,82) coincidió con 61 min de vigilia esa noche —de ahí que el umbral de anomalía bajara de -2σ a -1,5σ, pues con -2σ ni siquiera entraba a evaluarse— y las 2 muestras crudas de esa noche cayeron, en efecto, dentro de tramos Awake del export completo.
    30. Por qué varía tanto el HRV entre noches — fase de sueño en el instante de la lectura: cruzando 242 muestras reales de HRV con la fase de sueño activa en su instante exacto (export completo), se confirmó una diferencia real de hasta ~25% según la fase: REM 27,15 ms de media, sueño ligero 24,51 ms, sueño profundo 23,98 ms, despierto 21,85 ms. Con solo 1-2 muestras/noche, el resultado depende de qué fase concreta capturó el reloj. No se pudo filtrar por fase en el pipeline automático real (Health Auto Export) porque su JSON solo manda totales agregados de la noche por tipo de fase, no la fase activa en cada instante — solo el XML/ZIP completo tiene ese detalle. Por eso el primer intento de aviso basado únicamente en la ratio de vigilia de toda la noche se probó y se descartó: ese agregado en solitario no dice nada sobre si la muestra concreta cayó en vigilia. El mecanismo que sí se mantiene (bullet anterior) corrige ese fallo exigiendo ambas condiciones a la vez — anomalía estadística del valor Y vigilia prolongada — nunca la vigilia como criterio aislado.

    9. Autoría y titularidad

    Autor: Ricardo Manuel Trigo Calonge

    La presente obra incluye código fuente, arquitectura de software, modelo funcional y documentación técnica asociada.