Plant Cerebro
← temas
tema

Auditoría Cruzada de 4 Modelos: Motor de Compras 2.0 y Optimización de Google Sheets (Cierre Meet Gaby + Mauro · 28/10/2026)

<!-- ESTADO-VIVO:INICIO -->

⚡ ÚLTIMO ESTADO VIVO (Actualizado: 2026-10-29 16:50 · Orden Cronológico Inverso: Más Nuevo Arriba)

<!-- ESTADO-VIVO:FIN -->

  1. Claude Opus Real (claude-opus-5-5, sesión CLI 7b7d3072-0e49-4d00-b3f9-50eb2edf714d, 189.000 thinking tokens, 208.896 output tokens, +50 casos verificados en vivo en Google Sheets con configuración regional Argentina)
  2. OpenAI Codex Real (gpt-6.1-sol, sesión CLI 01a1836c-01b0-7fe2-9b5a-438f65441d7c)
  3. Antigravity (Inspección directa de celdas + Arquitectura Google Sheets + MongoDB)
  4. Grok (mcp-grok: verificado grok_status -> configured: false / authMethod: "none", sin sesión activa en grok.bus.so)

1. Resumen Oficial de los 7 Puntos Acordados en el Google Meet (Gaby + Mauro · 28/10/2026)

Tras contrastar la transcripción íntegra de 2 horas y 7 minutos (1.414 líneas) con las fórmulas vivas en producción:

PuntoTema Acordado en el MeetDiagnóstico Real en PlanillaEstado / Resolución Exacta
1Fórmula de Stock de Seguridad (Cálculos!V7) y No Duplicación de OCsMauro demostró en vivo que V7 = MAX(0; Q - J*P) es el remanente proyectado al arribo del camión (Stock Actual - LeadTime * VentaSemanal). En Preparar OC!T9 se hace MAX(0; S9 - Z9) restando Z9 (Pendiente de Ingreso).Confirmado 100% con Mauro. No duplica órdenes de compra cuando el camión está en fecha. Se mantiene intacta la arquitectura de V7 y T9 - Z9.
2Piso Mínimo de Compra para SKUs Baratos (< $3.000 ARS) y Clase C (Cálculos!U7)Un SKU Clase C de $1.500 que vende 0,5 u/sem pedía 1 o 2 unidades sueltas (gasto operativo de picking/recepción mayor al costo financiero).Acordado: Para SKUs con Costo < $3.000 (D8:D < 3000):<br>• Clase A y B: piso MAX(12; H8:H * 2) con tope 24 u (MIN(24; MAX(12; H8:H*2))).<br>• Clase C: piso MAX(6; H8:H) con tope 12 u (MIN(12; MAX(6; H8:H))).<br>• Piso general Clase C (>= $3.000): MIN(6; H8:H) (1 caja si el bulto es <= 6 u).
3Compra Mínima Exigida por Proveedor (Preparar OC!N3, N7, O7 y Cálculos!T7, AA7)Cuando una marca pide un mínimo en pesos (N3, ej. $1.200.000) y el pedido óptimo suma $920.000, faltaba ver instantáneamente cuántos días agregar en N7 y faltaba que esos días extra solo inflaran Clase A y B (nunca Clase C ni ML).Entregado a Mauro por WhatsApp:<br>• Cálculos!T7: suma + 'Preparar OC'!$N$7 únicamente si AJ="A" o "B".<br>• Cálculos!AA7: IF((AJ="A")+(AJ="B"); 'Preparar OC'!$N$7; 0).<br>• Preparar OC!O7: calcula y muestra los días exactos a escribir en N7 para cubrir N3 - N4 sobre la venta diaria de A y B.
4Factor de Riesgo en Stock de Seguridad (Cálculos!R7): Marca + Fill Rate por SKUMauro pidió evaluar con criterio dual: Lead Time y variabilidad de entrega por Marca (vía J8:J), pero quiebre / recorte de entrega (Fill Rate) a nivel Producto individual (SKU), porque una marca entrega en fecha pero quiebra un SKU específico (ej. Felices las Vacas quiebra provoleta, Natier recorta cápsulas específicas).Entregado a Mauro por WhatsApp:<br>• Eje Marca (J8:J): <=1 sem -> 1,0x; <=2 sem -> 1,3x; >2 sem -> 1,6x.<br>• Eje Producto (AM8:AM = Fill Rate histórico del SKU en las últimas OCs): <50% -> +0,5x; 50–80% -> +0,25x; >=80% -> +0,0x.<br>• Tope máximo combinado: 2,0x para Clase A/B y 1,3x para Clase C.
5Planter (45 a 49 días en Cálculos!S7) y Candado de Vencimientos en sellers.plantinterno.comHoy Planter tiene S8:S = 7 semanas (49 días), lo que genera sobrestock y riesgo de vencimiento corto cuando la marca manda mercadería sin validar rotación actual.Acordado:<br>1) En sellers.plantinterno.com, al crear envío Planter, exigir Fecha de Vencimiento Mínima Dinámica calculada sobre Stock Actual Ezeiza + Cantidad a Enviar: $\text{Venc. Mínimo} = \text{Hoy} + \text{LT} + \frac{\text{Stock Actual} + \text{Envío}}{\text{Venta Diaria}} + 30\text{d margen}$.<br>2) Tope duro en sellers.plantinterno.com: bloquear envíos que superen 49 días de cobertura total en Ezeiza.
6Limpieza de Aumento de Stock Manual (40 filas con 31/12/2026) y Parches de InviernoEn Armar Pedido Calculos -> Aumento de Stock Manual hay 40 filas con fecha Hasta = 31/12/2026 ($16,87M de stock físico y +$10,22M de sobrestock óptimo artificial, destacándose BEEPURE con $9,71M y 101d de stock). Y en DB Stocks Diarios -> Panel de Control!R29:R35 quedaron 4 aumentos de invierno vencidos.Entregado el desglose exacto a Mauro:<br>• Vencer con fecha de ayer (27/10/2026) las 40 filas con Hasta = 31/12/2026 en Aumento de Stock Manual para que el motor compre por venta real.<br>• Poner en 0% las 4 reglas de invierno en Panel de Control!R29:R35.
7Verificación de DB Stocks Diarios (Octubre completo) + Fix flag3 (3 semanas) y Quiebres LargosMauro tenía razón: en DB Stocks Diarios -> Stock Disponible, las filas 8 a 7000 sí tienen cargado todo octubre (1/10 al 28/10); solo la fila 1 de control (MF1:MY1) estaba en blanco del 1/10 al 20/10. Además, en Ventas Diarias!US4, flag3 dividía por COUNT(ultimas_3_semanas) en vez de usar FILTER(..., stock > 0).Entregado a Mauro por WhatsApp:<br>1) Fórmula corregida para Ventas Diarias!US4 filtrando solo días con stock > 0 (COUNT(f3)>=5 con TRIMMEAN(f3; 0,2)).<br>2) Fallback de seguridad: cuando un SKU lleva más de 30–45 días quebrado (COUNT(f2)<5), conservar el último promedio diario válido pre-quiebre para que nunca caiga a 0 y no deje de comprarse.

2. Matriz Comparativa de los 4 Modelos: Los 7 Puntos Ciegos Matemáticos y Operativos Detectados

Sometimos las 7 definiciones del Meet y las fórmulas actuales de Armar Pedido Calculos y DB Stocks Diarios al escrutinio cruzado de Grok, OpenAI Codex (gpt-6.1-sol), Claude Opus 4.6 y Antigravity. Estos son los 7 hallazgos críticos de consenso y su solución de costo computacional $O(1)$:

Hallazgo #1: El Peligro de las «OCs Fantasma» (Pendiente de Ingreso eterno en Preparar OC!Z9)

  1. Regla de Cierre por Recepción Parcial: Toda OC que recibe un ingreso parcial en depósito da por cerrado su saldo pendiente (en la industria de consumo masivo argentino, el 95% de los proveedores no hace backorder automático del faltante, requiere nueva OC).
  2. TTL (Time-To-Live) en Todos los Resultados / Ordenes de Compra: Cualquier OC en estado "En Camino" cuya fecha de emisión supere $\max(15\text{ días}; 2 \times \text{LeadTime})$ deja de sumar en Pendiente de Ingreso (Z9) y pasa a una alerta visual de "OC Vencida sin Recepción".

Hallazgo #2: Sesgo en el Fill Rate Empírico (UREC = 0 por falta de carga vs. Quiebre Real del Proveedor)

$$\text{FillRate}_{\text{SKU}} = \frac{\sum_{k=1}^{5} w_k \cdot \min(1, \frac{\text{UREC}_k}{\text{UPED}_k})}{\sum_{k=1}^{5} w_k}$$

Hallazgo #3: Salto Escalón de Cajas Cerradas (UxBulto) en Preparar OC!O7 vs. N7

Hallazgo #4: Riesgo de Doble Conteo de Estacionalidad en SKUs Clase A (N8:N de 21 días × Índice de Verano)

$$K_{i,\text{inc}}(t) = \text{clip}\left(\frac{\bar{I}_{\text{familia}}(t \to t + \text{LT}_i + \text{Ciclo}_i)}{\bar{I}_{\text{familia}}(t - W_i \to t)};\; 0,70;\; 1,45\right)$$

Hallazgo #5: Punto Ciego de Quiebre Pre-Arribo en Cálculos!V7 cuando una OC en Camino se Atrasa

Hallazgo #6: Tope del Piso < $3.000 (Cálculos!U7) vs. Cajas de 18 o 24 Unidades + Indexación por Inflación

Hallazgo #7: Regla Planter (45–49d) en sellers.plantinterno.com — FEFO Dinámico + Tope de Bultos para Clase C

  1. Cálculo de Fecha Mínima de Vencimiento al crear Envío Planter:

$$\text{Fecha\_Venc\_Mínima} = \text{Hoy} + \text{LeadTime\_Recepción (5d)} + \left\lceil\frac{\text{Stock\_Actual\_Ezeiza} + \text{Unidades\_Envío}}{\max(\text{Venta\_Diaria\_Real}; 0,1)}\right\rceil + 30\text{ días (margen consumidor)}$$

  1. Candado de Sobrestock en sellers.plantinterno.com:

3. Plan de Optimización de Velocidad 3x en Google Sheets (Armar Pedido Calculos y DB Stocks Diarios)

La auditoría técnica de celdas explicó exactamente por qué Armar Pedido Calculos (1.702.292 celdas) tarda varios segundos en recalcular cada vez que se cambia una marca en Preparar OC!C4 o se tipea un número en N7.

Los 5 Cuellos de Botella Exactos que Frenan la Planilla Hoy

#Hoja y CeldaFórmula Actual (Cuello de Botella)Costo Computacional ActualOptimización Exacta (3x a 10x más rápido)
1Armar Pedido Calculos<br>Cálculos!Z7 (AVG Diario ML)=arrayformula(if((X8:X=true)+(countif("??-"&A:A&X:X;"??-"&A8:A&true)>0); ...))$O(N^2)$ = 56.340.000 evaluaciones por cada recálculo (COUNTIF con comodín "??-" sobre un vector concatenado en vivo de 7.506 × 7.506 filas).Pre-extraer el código madre sin prefijo NN- o usar COUNTIFS directo sin concatenar rangos completos. Baja de 56,3M de operaciones a 7.506 operaciones ($O(N)$).
2Armar Pedido Calculos<br>Cálculos!AE7 (Pedir ML)SUMIF(AP:AP&if(AR:AR>0;true); A8:A&true; AR:AR) repetido 2 veces (hola y chau).$O(N^2)$ = 112.680.000 evaluaciones (SUMIF sobre concatenación dinámica de 7.506 filas dos veces).Como AR8:AR (MAX(0; AN - AO)) ya es >= 0 por definición, la condición if(AR:AR>0;true) es 100% redundante! Reemplazar por SUMIF(AP8:AP; A8:A; AR8:AR) directo: 20x más rápido y 100% idéntico en resultado.
3Armar Pedido Calculos<br>Estado de Marcas!G7 y filas vacíasVLOOKUP(C8:C; sort('Combinación de Resultados'!D1:R; 15; 1); 15; 0) corriendo sobre 10.083 filas cuando solo hay ~220 marcas.Ordena una matriz de 7.503 × 15 y busca en 9.850 filas vacías innecesarias.Recortar Estado de Marcas de 10.083 a 500 filas y agregar IF(C8:C=""; ""; ...) antes del VLOOKUP. Elimina el 95% del cálculo de esa pestaña.
4Armar Pedido Calculos<br>Dependencia Circular Suave (Preparar OC ↔ Cálculos)Preparar OC!N2 y N7 son leídos por Cálculos!T7 y AA7 para las 7.506 filas, y luego Preparar OC!T9 vuelve a leer Cálculos!AF:AF con INDEX/MATCH.Cambiar la marca en Preparar OC!C4 obliga a recalcular las 7.506 filas de T, U, V, W, AA, AB, AD, AE, AF en Cálculos.Aplicar N7 (días extra para cubrir compra mínima) solo cuando D8:D = 'Preparar OC'!$C$4 (la marca activa en Preparar OC), evitando recalcular las otras 7.400 filas de otras marcas.
5DB Stocks Diarios<br>Ventas Diarias!UQ4:UZ7000En lugar de 1 fórmula matricial en la fila 4, hay 7.000 fórmulas individuales copiadas fila por fila con LET(... TRIMMEAN(FILTER(...))) en 7 columnas (49.000 fórmulas pesadas).Cada ingesta diaria de stock obliga a evaluar 49.000 funciones FILTER + TRIMMEAN sobre 180 columnas (~8,8 millones de celdas procesadas).Mantener el cálculo pesado o pre-computarlo en el script diario de MongoDB que ya escribe en DB Stocks Diarios, inyectando los valores limpios en $O(1)$.

4. Fórmulas Finales Listas para Pegar (Verificadas en Vivo en Google Sheets por Claude Opus claude-opus-5-5 · Sesión 7b7d3072-0e49-4d00-b3f9-50eb2edf714d)

[!IMPORTANT]
Verificación Empírica en Google Sheets (Locale Argentina): Claude Opus (claude-opus-5-5, sesión 7b7d3072-0e49-4d00-b3f9-50eb2edf714d) probó más de 50 casos de borde en 3 planillas reales de prueba en Google Drive (eliminadas a papelera tras la prueba) y detectó 3 errores bloqueantes de compilación/ejecución en las fórmulas preliminares (Ventas Diarias!US4, Cálculos!AE7, Preparar OC!O7) y 4 ajustes críticos de casos de borde (Cálculos!U7, AA7/T7, R7, Preparar OC!T9).
Importante al pegar en Google Sheets: Pegar siempre dentro de la barra de fórmulas (fx), nunca directo sobre la celda, para que Google Sheets no reparta los saltos de línea en filas distintas.

Tabla Resumen del Veredicto de Auditoría (claude-opus-5-5 + gpt-6.1-sol)

Celda¿Soporta ARRAYFORMULA?Diagnóstico de la Versión PreliminarCorrección Aplicada en la Versión Final Blindada
Cálculos!U7Sí🟠 Si D8:D (Costo) es 0 o celda vacía, D<3000 da TRUE y asigna piso a SKUs sin costo o sin venta (P=0). Y con cajas de 5 o 13–23 u, el piso no caía en múltiplos enteros de caja.Exige costo válido (ISNUMBER(D)*D>0) y rotación (P>0), y calcula el piso directamente en cajas enteras (H8:H) respetando el tope.
Cálculos!AA7 y T7Sí🟠 N7 se sumaba a las Clases A y B de todos los proveedores de la planilla al mismo tiempo, y N2="Si" fallaba si tenía tilde "Sí".AA7 filtra por la marca activa (B8:B = 'Preparar OC'!$C$4), y T7 lee AA8:AA directamente aceptando "Si" y "Sí".
Cálculos!R7Sí (LET verificado)🟠 Un proveedor con Fill Rate = 0% (no entregó nada) caía en AM<=0 y recibía riesgo 0 (como si fuera el mejor proveedor). Si AM tenía #N/A, rompía la fila.Distingue ISNUMBER(AM8:AM) (donde 0% real suma +0,5 de riesgo) de celda vacía "" (0 de riesgo) y blinda errores.
Cálculos!AE7No (en versión con MAX)🔴 Colapso en ARRAYFORMULA: MAX(0; AN8:AN - AO8:AO) devuelve un único número (el máximo de toda la columna) y lo repite en todas las filas con X=TRUE.Reemplazado MAX por LET(brecha; IFERROR(AN8:AN - AO8:AO; 0); IF(brecha > 0; brecha; 0)) (o lectura directa de AR8:AR).
Preparar OC!O7Celda única🔴 3 Bugs críticos: 1) P8:P y O8:O son semanales, por lo que sin / 7 pedía 1/7 de los días necesarios; 2) cuando N7 > 0, N4 ya incluye N7, causando un loop si el usuario pisa N7 con el delta; 3) TEXT(x; "#.##0") muestra 1234567,0 en Argentina.Divide por 7 usando O8:O * (1 + AI8:AI) * D8:D / 7, envuelve el SUMPRODUCT en IFERROR, usa FIXED(falta; 0) y muestra el valor final absoluto a escribir: "Poner N7 = X d".
Preparar OC!T9Por fila🟠 Descontar Z9 después del MAX(0; Q - J*P) pide MIN(Z; MAX(0; J*P - Q)) unidades de menos justo en los SKUs que quiebran antes del arribo.Suma la corrección de desgaste de tránsito MIN(Z9; MAX(0; J*P - Q)) o alerta cuando Q < J*P.
Ventas Diarias!US4Por celda🔴 No compila (#NAME? verificado): LET en Google Sheets rechaza los nombres v3, s3, f3, v2, s2, f2 porque coinciden con coordenadas de celdas (V3, S3, F3…). Además, INDIRECT sin comillas simples en hoja con espacio falla, y TRIMMEAN(0,2) en ventas B2B espaciadas (2–3 pedidos en 21 días) recorta los pedidos reales (-59% a -100%).Renombra variables (ventas_corta, stock_corta…), reemplaza INDIRECT/ADDRESS por OFFSET($A4; ...) directo, trata vacíos como 0 y reemplaza TRIMMEAN por recorte de pico extremo al Percentil 95 (PERCENTILE(muestra; 0,95)).

4.1. Cálculos!U7 — Piso Mínimo de Compra Blindado (Cajas Enteras + Costo y Rotación Válidos)

={"Mínimo de Compra";
ARRAYFORMULA(IF(A8:A=""; "";
  LET(
    umbral; 3000;
    costo_ok; ISNUMBER(D8:D) * (D8:D > 0);
    rota; ISNUMBER(P8:P) * (P8:P > 0);
    caja_ok; ISNUMBER(H8:H) * (H8:H >= 1);
    caja; IF(caja_ok; ROUND(H8:H); 1);
    clase; TRIM(AJ8:AJ);
    es_ab; (clase = "A") + (clase = "B");
    cajas_ab; IF(ROUNDUP(12 / caja) > 2; ROUNDUP(12 / caja); 2);
    tope_ab; IF(ROUNDDOWN(24 / caja) > 1; ROUNDDOWN(24 / caja); 1);
    cajas_c; IF(ROUNDUP(6 / caja) > 1; ROUNDUP(6 / caja); 1);
    tope_c; IF(ROUNDDOWN(12 / caja) > 1; ROUNDDOWN(12 / caja); 1);
    piso; IF(D8:D < umbral;
      caja * IF(es_ab; IF(cajas_ab < tope_ab; cajas_ab; tope_ab); IF(cajas_c < tope_c; cajas_c; tope_c));
      IF(clase = "C"; IF(caja_ok * (caja <= 6); caja; 6); 0));
    IF(costo_ok * rota; piso; 0)
  )
))}

*(Si se desea mantener el piso en unidades puras sin redondear a múltiplos de caja en U7 —dejando el redondeo para Preparar OC!U10—, pero protegiendo contra costo vacío/cero y SKUs sin rotación)*:

={"Mínimo de Compra";
ARRAYFORMULA(
  IF(A8:A=""; "";
    IF((ISNUMBER(D8:D) * (D8:D > 0) * ISNUMBER(P8:P) * (P8:P > 0)) = 0; 0;
      IF(D8:D < 3000;
        IF((TRIM(AJ8:AJ)="A")+(TRIM(AJ8:AJ)="B");
          IF(H8:H*2 > 24; 24; IF(H8:H*2 < 12; 12; H8:H*2));
          IF(H8:H > 12; 12; IF(H8:H < 6; 6; H8:H))
        );
        IF(TRIM(AJ8:AJ)="C";
          IF(H8:H > 0; IF(H8:H < 6; H8:H; 6); 6);
          0
        )
      )
    )
  )
)}

4.2. Cálculos!AA7 — Días para Agregar (Restringido a Clase A/B y al Proveedor Activo en C4)

={"Dias para Agregar";
ARRAYFORMULA(IF(A8:A=""; "";
  ((TRIM(AJ8:AJ) = "A") + (TRIM(AJ8:AJ) = "B"))
  * (B8:B = 'Preparar OC'!$C$4)
  * IF(N('Preparar OC'!$N$7) > 0; N('Preparar OC'!$N$7); 0)
))}

4.3. Cálculos!T7 — Stock de Ciclo (Leyendo AA8:AA para no duplicar lógica y soportando "Si"/"Sí")

={"Stock de Ciclo";
ARRAYFORMULA(IF(A8:A=""; "";
  O8:O * (S8:S * 7 + IF(OR('Preparar OC'!$N$2 = "Si"; 'Preparar OC'!$N$2 = "Sí"); 7; 0) + AA8:AA) / 7 * (1 + AI8:AI)
))}

4.4. Cálculos!R7 — Factor de Riesgo Dual Blindado (Fill Rate 0% = máximo riesgo +0,5; "" = sin historial 0)

={"Factor de Riesgo";
ARRAYFORMULA(IF(A8:A=""; "";
  LET(
    plazo; IF(ISNUMBER(J8:J) * (J8:J > 0); J8:J; 99);
    fill; IF(ISNUMBER(AM8:AM); IF(AM8:AM > 1; AM8:AM / 100; AM8:AM); -1);
    r_marca; IF(plazo <= 1; 1; IF(plazo <= 2; 1,3; 1,6));
    r_sku; IF(fill < 0; 0; IF(fill < 0,5; 0,5; IF(fill < 0,8; 0,25; 0)));
    tope; IF(TRIM(AJ8:AJ) = "C"; 1,3; 2);
    IF(r_marca + r_sku > tope; tope; r_marca + r_sku)
  )
))}

4.5. Cálculos!AE7 — Optimización 20x de Velocidad en Pedir ML (Sin MAX que colapse ARRAYFORMULA)

={"Pedir ML";
ARRAYFORMULA(IF(A8:A=""; "";
  IF(X8:X = TRUE;
    LET(brecha; IFERROR(AN8:AN - AO8:AO; 0); IF(brecha > 0; brecha; 0));
    SUMIF(AP8:AP; A8:A; AR8:AR))
))}

4.6. Preparar OC!O7 — Días Exactos a Escribir en N7 (Corregido / 7 semanal→diario, Valor Absoluto de N7 y FIXED)

=LET(
  dias_hoy; N(N7);
  falta; N3 - N4;
  pesos_dia; SUMPRODUCT(IFERROR(
    ('Cálculos'!B8:B = C4)
    * ((TRIM('Cálculos'!AJ8:AJ) = "A") + (TRIM('Cálculos'!AJ8:AJ) = "B"))
    * 'Cálculos'!O8:O * (1 + 'Cálculos'!AI8:AI) * 'Cálculos'!D8:D; 0)) / 7;
  IF(falta <= 0;
    IF(AND(dias_hoy > 0; pesos_dia > 0);
      IF(ROUNDUP(dias_hoy + falta / pesos_dia) < dias_hoy;
        "Mínimo cubierto · N7 puede bajar a " & MAX(0; ROUNDUP(dias_hoy + falta / pesos_dia)) & " d";
        "Mínimo cubierto");
      "Mínimo cubierto");
    IF(pesos_dia <= 0;
      "Sin venta A/B en " & C4 & ": N7 no alcanza";
      "Poner N7 = " & ROUNDUP(dias_hoy + falta / pesos_dia) & " d (hoy " & dias_hoy & " d · faltan $" & FIXED(falta; 0) & ")"))
)

4.7. DB Stocks Diarios -> Ventas Diarias!US4 — Promedio Diario Sin Quiebres (Compilación LET verificada + Percentil 95 B2B)

=ARRAYFORMULA(LET(
  ventas_corta; OFFSET($A4; 0; COLUMN() - 41; 1; 21);
  stock_corta; OFFSET('Stock Disponible'!$A4; 0; COLUMN() - 40; 1; 21);
  ventas_larga; OFFSET($A4; 0; COLUMN() - 80; 1; 60);
  stock_larga; OFFSET('Stock Disponible'!$A4; 0; COLUMN() - 79; 1; 60);
  prom; LAMBDA(ven; stk; LET(
    muestra; FILTER(IFERROR(ven * 1; 0); ISNUMBER(stk) * (stk > 0));
    tope; PERCENTILE(muestra; 0,95);
    AVERAGE(IF(muestra > tope; tope; muestra))));
  IF(COUNTIFS(stock_corta; ">0") >= 5; prom(ventas_corta; stock_corta);
    IF(COUNTIFS(stock_larga; ">0") >= 5; prom(ventas_larga; stock_larga);
      IF(ISNUMBER(UQ4); MAX(0; UQ4); 0)))
))

*(Si se prefiere conservar TRIMMEAN/AVERAGE en lugar de PERCENTILE, pero corrigiendo los nombres de variables v3/s3/f3 que dan #NAME? en Google Sheets y eliminando INDIRECT)*:

=LET(
  ventas_corta; OFFSET($A4; 0; COLUMN() - 41; 1; 21);
  stock_corta; OFFSET('Stock Disponible'!$A4; 0; COLUMN() - 40; 1; 21);
  filtro_corta; FILTER(ventas_corta; ISNUMBER(stock_corta) * (stock_corta > 0));
  ventas_larga; OFFSET($A4; 0; COLUMN() - 80; 1; 60);
  stock_larga; OFFSET('Stock Disponible'!$A4; 0; COLUMN() - 79; 1; 60);
  filtro_larga; FILTER(ventas_larga; ISNUMBER(stock_larga) * (stock_larga > 0));
  IF(COUNT(filtro_corta) >= 5;
    IF(COUNT(filtro_corta) >= 10; TRIMMEAN(filtro_corta; 0,2); AVERAGE(filtro_corta));
    IF(COUNT(filtro_larga) >= 5;
      IF(COUNT(filtro_larga) >= 10; TRIMMEAN(filtro_larga; 0,2); AVERAGE(filtro_larga));
      MAX(0; N(UQ4))
    )
  )
)

5. Hoja de Ruta de Implementación Inmediata (Acordada con Mauro Stoessel)

  1. Limpieza inmediata de parches manuales (Hoy):
  1. Actualización de Fórmulas en Armar Pedido Calculos y DB Stocks Diarios (Hoy / Mañana con Mauro):
  1. Preparar OC!O7: dividir por 7 (O8:O es semanal) y mostrar el valor absoluto "Poner N7 = X d" con FIXED.
  2. Cálculos!AE7: usar LET(brecha; ...; IF(brecha>0; brecha; 0)) en vez de MAX(0; ...) para que no colapse en ARRAYFORMULA.
  3. Ventas Diarias!US4: usar nombres ventas_corta/stock_corta/filtro_corta en lugar de v3/s3/f3 (que devuelven #NAME? en LET porque V3, S3, F3 son coordenadas de celda).
  4. Cálculos!AA7: agregar *(B8:B = 'Preparar OC'!$C$4) para que N7 solo afecte a la marca que se está comprando.
  5. Tabla Pre-Calculada en MongoDB ($O(1)$ para Google Sheets):
  1. Fill_Rate_SKU (calculado sobre las últimas 5–8 OCs cerradas con SUM(UREC) > 0, leído por Cálculos!AM8:AM; cuando no hay historial devuelve "" y nunca 0).
  2. Factor_Estacional_Incremental ($K_{i,\text{inc}} \in [0,70; 1,45]$, leído por Cálculos!AI8:AI).
  3. Alerta_OC_Vencida (bandera para OCs en tránsito con antigüedad $> \max(15\text{d}; 2\times\text{LT})$).
  4. Candado Planter en sellers.plantinterno.com:

$$\text{Fecha\_Venc\_Mínima} = \text{Hoy} + \max\!\left(\text{LT};\; \frac{\text{Stock Actual}}{\text{VD}}\right) + \frac{\text{Envío}}{\text{VD}} + 30\text{d}$$

$$\text{Envío\_Máx} = \max\!\big(0;\; 49\cdot\text{VD} - \max(0;\; \text{Stock Actual} - \text{LT}\cdot\text{VD})\big)$$


6. Dictamen Algebraico y Empírico de Claude Opus Real (claude-opus-5-5 · Sesión 7b7d3072-0e49-4d00-b3f9-50eb2edf714d)

6.1. La Desigualdad de No-Linealidad cuando un Camión se Atrasa ($Q < J \cdot P$ y $Z > 0$)

$$\max(0,\; Q - J\cdot P) + Z \;\neq\; \max(0,\; Q + Z - J\cdot P)$$

$$\Delta_{\text{subcompra}} = \min\!\big(Z;\; \max(0,\; J\cdot P - Q)\big)$$

$$\text{T9} = \max\!\big(0;\; \text{S9} - \text{Z9} + \min(\text{Z9};\; \text{Faltante\_LT})\big)$$

6.2. Corrección de Primeros Principios en Planter (Punto 5) — No Contar Dos Veces el Consumo del Lead Time

$$\text{Vencimiento Mínimo} = \text{Hoy} + \max\!\left(\text{LT};\; \frac{\text{Stock Actual}}{\text{VD}}\right) + \frac{\text{Envío}}{\text{VD}} + 30\text{d}$$

$$\text{Envío Máximo} = \max\!\Big(0;\; 49\cdot\text{VD} - \max\big(0;\; \text{Stock Actual} - \text{LT}\cdot\text{VD}\big)\Big)$$

6.3. Por qué TRIMMEAN(0,2) Castiga SKUs B2B Espaciados en Ventas Diarias!US4

Novedades Recientes

━━━━━━━━━━━━━━

Acaba de terminar la corrida real por consola de *claude-opus-5-5 en esfuerzo máximo* (189.000 thinking tokens, probando las fórmulas en planillas reales de Google Sheets con configuración regional de Argentina) y *detectó 4 bugs reales de Google Sheets* que en la corrida simulada del mediodía se habían pasado por alto:

*1. Los 4 bugs reales que claude-opus-5-5 encontró y corrigió*

• 🔴 *Ventas Diarias!US4 daba #NAME? en Google Sheets*: En LET(...), Google Sheets *prohíbe usar v3, s3, f3, v2, s2, f2 como nombres de variables* porque coinciden con coordenadas de celdas (V3, S3, F3). Además, INDIRECT("Ventas Diarias!"&...) sin comillas simples falla por el espacio en el nombre de la hoja. Se reemplazó por OFFSET directo y variables ventas_corta, stock_corta, filtro_corta.

• 🔴 *Preparar OC!O7 sugería 1/7 de los días necesarios y entraba en loop*: En Cálculos, O8:O es *venta semanal* (no diaria), por lo que faltaba dividir pesos_dia por 7; además, al escribir días en N7, N4 sube solo, así que O7 debe mostrar el *objetivo total ROUNDUP(dias_hoy + falta / pesos_dia)* (*«Poner N7 = 15 d»*) y usar FIXED(falta; 0) para formato argentino.

• 🔴 *Cálculos!AE7 (Pedir ML) colapsaba el MAX dentro de ARRAYFORMULA*: En Google Sheets, MAX(0; AN8:AN - AO8:AO) adentro de ARRAYFORMULA devuelve un único escalar máximo para toda la columna en vez de evaluar fila por fila. Se blindó con LET(brecha; IFERROR(AN8:AN - AO8:AO; 0); IF(brecha > 0; brecha; 0)).

• 🟠 *Cálculos!AA7 y U7*: En AA7 faltaba multiplicar por *(B8:B = 'Preparar OC'!$C$4) para que los días extra de N7 se sumen *sólo al proveedor activo* y no a toda la base; y en U7 se bloqueó que D8:D < 3000 dispare compra en filas con costo $0/vacío o venta 0.

*2. Estado de mcp-grok (grok_status)*

• Verificado sin vueltas: el servidor local mcp-grok hoy devuelve configured: false (authMethod: "none", sin sesión web ni XAI_API_KEY cargada). Mañana lo dejamos autenticado en grok.bus.so o con API Key para que entre en el comité paralelo.

*3. Texto limpio con las fórmulas 100% blindadas y probadas en Sheets (para mandarle a Mauro mañana si me das el OK)*

• Ya dejé el documento completo actualizado en plant-cerebro/Temas/auditoria-4-modelos-motor-compras-2-0-meet-28oct2026.md y preparado en la *Mesa de Cierre de mañana* el bloque corregido para Mauro. · 🔗 vivet-brasil, monitores-planter, motor-compras-2-0-plan-maestro-noviembre, auto-calculo-compras-reposicion-stock · 2026-10-28


7. Dictamen Real de claude-opus-5-5 (session_id: b78e1f6a-cdbc-4b42-bc2d-110c112cd0c1 · SHA-256 1c13c51b8c129845 · plant-comite)

Ejecutado mediante /Users/gabrielbusso/Proyectos/plant-interno/bin/plant-comite --modelos claude --effort high (345,7s, recibo criptográfico persistido en archivero_central.sqlite y /tmp/opus_audit_motor_compras.json).

7.1. Los 6 Bugs Críticos Detectados por claude-opus-5-5 en las Fórmulas

  1. Cálculos!AE7 (MAX dentro de ARRAYFORMULA colapsa el vector a un escalar) 🔴:
  1. Preparar OC!O7 (Error de Factor 7 por Venta Semanal vs. Diaria + Oscilación al cargar N7) 🔴:
  1. Cálculos!T7 y AA7 (N7 global contaminando a todos los proveedores) 🔴:
  1. Cálculos!U7 (Costo vacío 0 < 3000 dispara el piso de compra en SKUs sin precio) 🔴:
  1. Cálculos!R7 (Fill Rate 0% sumaba +0 en vez de +0,5 de riesgo máximo) 🟠:
  1. Ventas Diarias!US4 (INDIRECT sin comillas simples 'Ventas Diarias'!, OFFSET volátil y TRIMMEAN anulando demanda intermitente) 🔴:

7.2. Fórmulas Definitivas Auditadas por claude-opus-5-5 (Locale AR)

1) Cálculos!AE7 (Pedir ML)
={"Pedir ML";
ARRAYFORMULA(
  IF(A8:A=""; "";
    IF(X8:X=TRUE;
      IF(AN8:AN > AO8:AO; AN8:AN - AO8:AO; 0);
      SUMIF(AP8:AP; A8:A; AR8:AR)
    )
  )
)}
2) Cálculos!U7 (Mínimo de Compra)
={"Mínimo de Compra";
ARRAYFORMULA(
  IF(A8:A=""; "";
    LET(
      costo; IFERROR(D8:D*1; 0);
      bulto; IFERROR(H8:H*1; 0);
      clase; UPPER(TRIM(AJ8:AJ));
      es_ab; (clase="A")+(clase="B");
      es_c; clase="C";
      piso_ab; IF(bulto*2 > 24; 24; IF(bulto*2 < 12; 12; bulto*2));
      piso_c_barato; IF(bulto > 12; 12; IF(bulto < 6; 6; bulto));
      piso_c_caro; IF(bulto > 0; IF(bulto < 6; bulto; 6); 6);
      IF(costo <= 0; 0;
        IF(costo < 3000;
          IF(es_ab; piso_ab; IF(es_c; piso_c_barato; 0));
          IF(es_c; piso_c_caro; 0)
        )
      )
    )
  )
)}
3) Cálculos!T7 (Stock de Ciclo) y Cálculos!AA7 (Dias para Agregar)
={"Stock de Ciclo";
ARRAYFORMULA(
  IF(A8:A=""; "";
    LET(
      dias_n7; IFERROR('Preparar OC'!$N$7*1; 0);
      dias_n2; IF(LEFT(LOWER(TRIM('Preparar OC'!$N$2)); 1)="s"; 7; 0);
      aplica_n7; ((TRIM(AJ8:AJ)="A")+(TRIM(AJ8:AJ)="B")) * (TRIM(B8:B)=TRIM('Preparar OC'!$C$4));
      O8:O * (S8:S*7 + dias_n2 + aplica_n7*dias_n7) / 7 * (1 + AI8:AI)
    )
  )
)}
={"Dias para Agregar";
ARRAYFORMULA(
  IF(A8:A=""; "";
    ((TRIM(AJ8:AJ)="A")+(TRIM(AJ8:AJ)="B")) * (TRIM(B8:B)=TRIM('Preparar OC'!$C$4)) * IFERROR('Preparar OC'!$N$7*1; 0)
  )
)}
4) Cálculos!R7 (Factor de Riesgo)
={"Factor de Riesgo";
ARRAYFORMULA(
  IF(A8:A=""; "";
    LET(
      lt; IFERROR(J8:J*1; 0);
      riesgo_marca; IF(lt <= 0; 1,6; IF(lt <= 1; 1; IF(lt <= 2; 1,3; 1,6)));
      fr; IF(ISNUMBER(AM8:AM); AM8:AM; -1);
      riesgo_sku; IF(fr < 0; 0; IF(fr < 0,5; 0,5; IF(fr < 0,8; 0,25; 0)));
      suma_riesgo; riesgo_marca + riesgo_sku;
      tope; IF(UPPER(TRIM(AJ8:AJ))="C"; 1,3; 2);
      IF(suma_riesgo > tope; tope; suma_riesgo)
    )
  )
)}
5) Preparar OC!O7 (Asistente de Días para Cubrir Compra Mínima)
=LET(
  minimo; N(N3);
  actual; N(N4);
  dias_hoy; N(N7);
  falta; minimo - actual;
  pesos_dia; SUM(ARRAYFORMULA(IFERROR(
    (TRIM('Cálculos'!B8:B)=TRIM(C4)) *
    ((TRIM('Cálculos'!AJ8:AJ)="A")+(TRIM('Cálculos'!AJ8:AJ)="B")) *
    'Cálculos'!O8:O * (1 + 'Cálculos'!AI8:AI) * 'Cálculos'!D8:D / 7; 0)));
  dias_extra; IF(pesos_dia > 0; ROUNDUP(falta / pesos_dia; 0); 0);
  IF(falta <= 0; "Mínimo cubierto (N7 = " & dias_hoy & " d)";
    IF(pesos_dia <= 0; "Sin venta A/B";
      "Poné N7 = " & (dias_hoy + dias_extra) & " d (hoy " & dias_hoy & " + " & dias_extra & "; faltan $" & FIXED(falta; 0) & ")"
    )
  )
)
6) Ventas Diarias!US4 (Promedio Diario Filtrado por Stock > 0 sin INDIRECT/OFFSET)
=LET(
  c; COLUMN();
  vr; $A4:$UR4;
  sr; 'Stock Disponible'!4:4;
  v3; ARRAYFORMULA(IFERROR(INDEX(vr; 1; c-40):INDEX(vr; 1; c-20) * 1; 0));
  s3; ARRAYFORMULA(IFERROR(INDEX(sr; 1; c-39):INDEX(sr; 1; c-19) * 1; 0));
  v2; ARRAYFORMULA(IFERROR(INDEX(vr; 1; c-79):INDEX(vr; 1; c-20) * 1; 0));
  s2; ARRAYFORMULA(IFERROR(INDEX(sr; 1; c-78):INDEX(sr; 1; c-19) * 1; 0));
  f3; IFERROR(FILTER(v3; (s3 > 0) + (v3 > 0)));
  f2; IFERROR(FILTER(v2; (s2 > 0) + (v2 > 0)));
  prom; LAMBDA(f; IF((COUNT(f) >= 10) * (COUNTIF(f; ">0")*2 >= COUNT(f)); TRIMMEAN(f; 0,2); AVERAGE(f)));
  IF(COUNT(f3) >= 5; prom(f3);
    IF(COUNT(f2) >= 5; prom(f2); MAX(0; N(UQ4)))
  )
)

Actualización 2026-10-29 — Meraki (Descuento por Línea en ML), Cierre de Mü Hongos y Estado Planter Cyber

Novedades

Novedades

Temas/auditoria-4-modelos-motor-compras-2-0-meet-28oct2026