# Briefing para Claude Code — Fermenty · Reconciliar con el Afinador e implementar el motor

> **Este briefing corrige y sustituye** partes de `Briefing_ClaudeCode_Ficha_Motor.md` (ejecutado,
> commit `83b6d6d`) y **cancela por completo** `Briefing_ClaudeCode_Ficha_pH.md`.
>
> Documentos de referencia obligatorios:
> - **`docs/Matematica_Motor.md`** — la matemática entera extraída del prototipo. Léelo antes
>   que este briefing; aquí no se repiten las fórmulas.
> - **`docs/afinador.py`** — transcripción ejecutable y verificada, que produce la tabla dorada de §9.
>
> Fecha: 2026-07-23 · Proyecto: Fermenty (ZYMOLAB SLU)

---

## 1. Qué ha pasado

La ficha del paso 7 se especificó a partir de conversaciones de diseño, no del prototipo. **El prototipo existía desde el principio** y contiene un modelo bastante más completo. Al leerlo aparecieron nueve divergencias, y no son de calibración: son de modelo.

> **Manda el Afinador.** Es el modelo real, validado contra el obrador. Lo que contradiga a `docs/Matematica_Motor.md` está mal, incluidos los briefings anteriores y esta frase si algún día deja de cuadrar.

**Lo que NO hay que rehacer** —y conviene decirlo porque parece que sí—:

- **Los seis pasos de esquema.** El Afinador no toca clasificaciones, guías, recetas ni tandas. Están bien.
- **La columna `ficha` como JSON.** La regla «columnas donde el motor no llega, JSON donde sí» se puso exactamente para esto: cambiar de dos ejes a cuatro es contenido distinto en el mismo sitio, **sin migración**.
- **`App\Mentor` como servicio** y la cadena de herencia. Sigue en pie, con un matiz en §4.3.
- **Las columnas del motor en `batches`.** No se crearon en el paso 6 precisamente porque su forma dependía del contrato. Si se hubieran creado, ahora estarían mal.

**Lo que sí hay que rehacer:** el contenido de la ficha, el formulario del admin, y los perfiles de ingrediente.

---

## 2. 🔴 Cancelado

`Briefing_ClaudeCode_Ficha_pH.md` **no se ejecuta**. Motivo: proponía una tabla de puntos interpolados para convertir pH ↔ acidez, y el Afinador ya resuelve el pH con una **fórmula logarítmica** (`docs/Matematica_Motor.md` §9):

```
pH = clamp(3,9 − 0,55 × ln(ácido / 2,5) , 2,4 → 4,9)
```

Implementarlo sería crear un segundo dueño del mismo hecho. La fórmula gana.

**Lo que sí sobrevive de aquel briefing**, porque sigue siendo cierto y es requisito del propietario:

- **Un pH medido por el usuario se guarda como pH**, nunca convertido. La conversión ocurre al calcular.
- **Más ácido = pH más bajo.** Sigue siendo fuente clásica de signos invertidos; merece un test.

---

## 3. Las nueve divergencias

Están tabuladas en `docs/Matematica_Motor.md` §11. Resumen de lo que implican:

| Divergencia | Consecuencia |
|---|---|
| Temperatura lineal → **Q10 = 2,0** | La ficha declara qué modelo usa (§4.3) |
| Dos ejes → **cuatro** + tres elecciones | Reescribir `perfiles_objetivo` |
| Presión no modelada → **sí, con Henry** | Bloque nuevo en la ficha |
| pH por tabla → **fórmula logarítmica** | Cancela el briefing de pH |
| Barandilla de cantidad → **margen temporal** | Mejor que la nuestra; ver §4.4 |
| Escala descartada → **existe** (`horasPor100L`) | Bloque nuevo |
| Perfil de ingrediente de 2 ejes → **3 por papel** | Reescribir `ingredients.profile` (§5) |
| Suelo de identidad → **no existía** | Concepto nuevo, importante |
| ABV fuera → **se calcula y va soldado a la presión** | El motor lo calcula; los umbrales legales siguen en `AbvCompliance` |

---

## 4. La ficha nueva

### 4.1 · Espejo del prototipo

**La estructura debe ser la del `FICHA` del Afinador**, con los nombres en claro que ya usa. No inventes una capa de traducción: cuanto más se parezcan, más fácil es ver si divergen.

Todas las constantes de `docs/Matematica_Motor.md` §2 van a la ficha. Los seis presets de §1 van como lista editable, cada uno con sus cuatro ejes y sus tres elecciones.

### 4.2 · La ficha no es una plantilla común

Consecuencia de fondo que cambia cómo se construye el admin: **cada fermento tiene su propio modelo.** La kombucha usa el del Afinador; el chucrut se parecerá más a `BrineCalculator` (salinidad base + perfil crujiente/normal/suave), y eso no cabe en los mismos campos.

Así que el admin **no puede ser un formulario fijo**. Propón cómo resolverlo: un formulario que se adapta al modelo declarado en la ficha, o un editor por bloques. **Punto de parada: no lo implementes sin confirmación.**

### 4.3 · Dos modelos de temperatura, no dos juegos de números

La cadena de herencia del paso 7 (`RespuestaTemperatura::BASE` → ficha) se diseñó para heredar **valores**. Ahora hay dos **modelos**:

- **Lineal** — 0,05/°C por encima, 0,06/°C por debajo, topes 0,6–1,6. Lo heredan las siete guías sin ficha.
- **Q10** — `2,0 ^ ((T − 23) / 10)`. Es el de kombucha.

La ficha debe **declarar qué modelo usa**, y `App\Mentor` resolver ambos. Sin ficha se sigue heredando el lineal, así que las otras guías no se rompen.

### 4.4 · La barandilla es temporal, y es mejor que la nuestra

Fuera `carbohidrato_max_al_cerrar_g_l`. El Afinador no limita cuánto azúcar entra: exige **al menos un día de margen entre el punto perfecto y el peligroso** (`margenMin`). Protege sin prohibir, y encaja con el criterio del propietario de ofrecer recetas en rangos sanos en vez de poner topes.

El umbral de 8 bar es **de aviso, no de prohibición**, y depende de la botella. El propio prototipo lo dice. Que el mensaje lo mantenga.

---

## 5. Los perfiles de ingrediente

Las tablas `AZUCAR`, `TE` y `SABOR` del prototipo **son perfiles de ingrediente**, y su sitio es `ingredients.profile` — no la ficha. Un solo dueño: lo que aporta un ingrediente viaja con el ingrediente.

Los campos dependen del papel, y eso está bien porque es JSON:

- **Azúcar** (`sustrato`) — `carbPorG`, `velocidad`, `aroma`
- **Té** (`medio`) — `aroma`, `cuerpo`. **No aporta carbohidrato**: no toca S₀, ni gas, ni presión, ni ABV.
- **Saborizante** — `carbPorG`, `dosis`, `simple`

**Reconciliar con lo sembrado en el paso 5**, que usaba `fermentable_carb_per_unit` y `acid_per_unit`. Gana la nomenclatura del Afinador. Y ojo con dos cosas:

- **`acid_per_unit` del líquido de arranque no lo usa el Afinador.** El prototipo deriva el pH inicial del *porcentaje* de arrancador: `pHInicial = clamp(5,6 − 0,06 × arrancador, 3,8 → 5,6)`. Esa fórmula va en la ficha y el campo del ingrediente sobra. Confírmalo antes de quitarlo.
- **Faltan variantes en el catálogo**: panela, miel, fructosa, té blanco, té rojo, y las formas de saborizante. Propón el árbol y espera confirmación (mismo criterio del paso 5: un nivel existe si cambia el cálculo, una barandilla o lo que se compra — aquí todas cambian el cálculo).

---

## 6. Alcance

**Fase A — reconciliar los datos.** La ficha nueva, los perfiles de ingrediente, el admin. Sin motor.

**Fase B — el motor.** `App\Mentor` implementando `docs/Matematica_Motor.md` §4–10 como función pura.

**Punto de parada entre A y B.** No empieces B sin confirmación: si la forma de la ficha está mal, es mejor descubrirlo antes de construir encima.

**Fuera de las dos fases:**
- Las columnas de formulación en `batches` (perfil objetivo, contexto, ficha congelada). Van cuando el contrato del motor esté verificado.
- La pantalla de formular.
- El catálogo de trueques con sus plantillas de voz — aunque el prototipo ya trae los textos y son buenos, ver §8.
- Fichas de los otros fermentos.

---

## 7. Fase A — Los cambios

**7.1 · Commitear `docs/Matematica_Motor.md`** si no está. Es la referencia de todo lo demás.

**7.2 · Proponer la ficha nueva** ⛔ · Punto de parada. Espejo del prototipo, con el modelo de temperatura declarado.

**7.3 · Proponer el admin adaptable** ⛔ · Punto de parada. Ver §4.2.

**7.4 · Migrar la ficha de kombucha** a la estructura nueva, con los valores del prototipo. **Éstos sí los tienes**: están en el código del Afinador y no hay que preguntárselos al propietario. Marca en `meta.origen` que salen de `afinador-kombucha_9.jsx`.

**7.5 · Ampliar el catálogo de ingredientes** con las variantes que faltan, y reescribir los perfiles con la nomenclatura del Afinador.

**7.6 · Retirar lo que el Afinador no usa** — `acidez_inicial_arranque` y `carbohidrato_max_al_cerrar_g_l`, con confirmación previa.

---

## 8. Fase B — El motor

**8.1 · `App\Mentor` como función pura.** Entra ficha + elecciones + contexto, sale el resultado. Sin estado, sin base de datos dentro del cálculo. Así se puede testear con tabla de casos.

**8.2 · Tests contra el ancla.** El caso de referencia —70 g/L, 6 g/L té, 10 % arrancador, 23 °C— debe dar **7–8 días**. Ese test es la primera línea de defensa contra una transcripción mal hecha.

Añade casos de los extremos: el suelo de identidad (que dispara el aviso en vez de inflar el azúcar), el margen por debajo de un día, y la temperatura fuera de banda viable.

**8.3 · Los avisos y trueques del prototipo son contenido, no código.** Están redactados y son buenos — el propietario los escribió con voz de mentor. Trasládalos tal cual, pero **fuera de los `if`**: cada uno es una condición más un mensaje, que es exactamente la forma de `notification_rules`. No los incrustes en el servicio.

**8.4 · Nada de la ficha viaja al cliente.** El motor devuelve cantidades, ventanas, avisos y trueques. Nunca coeficientes.

---

## 9. Valores de referencia verificados — úsalos como tests

La matemática de `docs/Matematica_Motor.md` se transcribió a Python (`docs/afinador.py`) y se ejecutó. **Estos son los resultados. Son la tabla dorada contra la que comparar la implementación PHP.**

El ancla sale exacta, lo que confirma que la transcripción es fiel: **pH inicial 5,0 clavado y 7,7 días**, contra los «pH 5 · 7–8 días» del obrador.

**Los seis presets a 23 °C, volumen 3 L:**

| preset | S0 | arr % | progreso | días | ventana F1 | pH | ABV |
|---|---|---|---|---|---|---|---|
| suave | 67,6 | 10,8 | 0,41 | 5,2 | 5,0–6,3 | 3,75 | 0,29 |
| comercial | 100,3 | 18,1 | 0,38 | 4,2 | 5,0–6,0 | 3,57 | 0,67 |
| equilibrada | 75,6 | 10,2 | 0,52 | 7,7 | 7,0–9,3 | 3,55 | 0,39 |
| complejo | 76,3 | 8,1 | 0,57 | 10,2 | 9,2–12,3 | 3,50 | 0,33 |
| ácida | 66,6 | 8,9 | 0,80 | 13,2 | 11,9–15,9 | 3,38 | 0,27 |
| fuerte | 93,9 | 8,9 | 0,63 | 12,1 | 10,9–14,5 | 3,33 | 0,65 |

**Equilibrada por temperatura:**

| °C | 18 | 20 | 22 | 23 | 25 | 28 | 30 |
|---|---|---|---|---|---|---|---|
| días | 10,9 | 9,5 | 8,3 | 7,7 | 6,7 | 5,5 | 4,8 |

**Dos casos límite que ya aparecen y hay que testear:**

- **`comercial` dispara el suelo de identidad**: 4,2 días de cinética contra el mínimo de 5. El motor **no debe inflar el azúcar**; debe calcular el desenlace real y avisar. Es la carta que más pide un principiante, así que este camino se va a recorrer mucho.
- **`comercial` y `fuerte` pasan de 0,5 % ABV**, el umbral de etiquetado. No es un fallo: es información que el mentor tiene que dar.

**Aviso sobre el alcance de la referencia Python:** cubre §4, 5, 6, 8 y 9 de la matemática — presupuesto, F1, cierre, alcohol y química. **No** implementa la presión de §7 ni los derivados de §10 (complejidad, ritmo de cata, burbuja), ni los avisos. Esos hay que transcribirlos del prototipo directamente y no tienen tabla dorada todavía.

---

## 10. Criterios de aceptación

- [ ] `docs/Matematica_Motor.md` está en el repo y la ficha lo espeja
- [ ] La ficha de kombucha tiene los cuatro ejes, las tres elecciones y todas las constantes del prototipo
- [ ] El modelo de temperatura está declarado y `App\Mentor` resuelve lineal y Q10
- [ ] Las siete guías sin ficha siguen heredando el lineal, sin romperse
- [ ] Los perfiles de ingrediente usan la nomenclatura del Afinador
- [ ] No existe ninguna tabla de conversión pH ↔ acidez
- [ ] El caso de referencia da 7,7 días y pH inicial 5,0
- [ ] Los seis presets coinciden con la tabla dorada de §9 (tolerancia ±0,1)
- [ ] `comercial` dispara el suelo de identidad y avisa, sin inflar el azúcar
- [ ] Los avisos y trueques son condición + mensaje, no `if` incrustados
- [ ] Ningún endpoint devuelve la ficha
- [ ] Nada añadido «por si acaso»

---

## 11. Reportar

Tres paradas: 7.2, 7.3, y el fin de la fase A antes de empezar B.

Si algún valor de la tabla dorada de §9 no cuadra, **para y dilo**: significa que la transcripción PHP y la referencia divergen, y eso hay que resolverlo antes de seguir construyendo encima.

Y el apartado de siempre: **dónde los datos contradijeron el briefing.** Esta vez el briefing anterior ya contradijo la realidad, así que con más motivo.

### Para el propietario

1. **Los coeficientes «a dedo»** — el prototipo marca las tablas de azúcar, té y saborizante como pendientes de backtest. Son los primeros candidatos a moverse.
2. **El backtest ya se puede evaluar a mano.** Con `docs/Matematica_Motor.md` escrito, las tandas recordadas se contrastan sin necesidad de código — y ése era el orden correcto desde el principio.
