# Contexto para validar la auditoria Sentry del 2026-09-29

Este documento resume lo investigado y desplegado. No asumir que un issue con
estado `unresolved` significa que sigue ocurriendo: separar estado historico,
ultimo evento y evidencia runtime.

## Estado real

- La app fue validada con Playwright sin puerto en
  `http://demo.enterfarmaplus.test/login`: login correcto; Dashboard, POS,
  Items y Documents devolvieron HTTP 200. Tambien respondieron 200
  `/pos/tables`, `/pos/payment_tables` y `/documents/records`. No hubo errores
  de consola.
- Produccion tiene aproximadamente 30 GB libres. Logs diarios y sesiones
  escriben con `www-data`; no se borro informacion.
- `DIGEMID_CATALOG_AUTO_SYNC=false`; el scheduler no lista el job DIGEMID y el
  sidecar esta detenido porque el servidor no puede superar el challenge de
  Cloudflare del portal oficial.
- El catalogo oficial se descargo con Playwright y se sincronizo limpiamente:
  18,240 registros.

## DIGEMID: FARMA-9E y FARMA-AX

### Causa de FARMA-AX

El evento `FARMA-AX` reporto `Catalogo rechazado: 5747 registros; minimo
esperado 15713` a las 14:17 UTC. La causa fue una carrera: dos comandos
`digemid:sync-catalog` borraban y reutilizaban la misma tabla staging global.
Una ejecucion veia el staging incompleto mientras otra importaba el archivo
completo de 18,240 filas.

### Correccion

`app/Console/Commands/SyncDigemidCatalogCommand.php` ahora toma un lock
advisory MariaDB con `GET_LOCK('sysfarma:digemid:sync-catalog', 0)` y libera con
`RELEASE_LOCK`. Una ejecucion concurrente se omite con exito, sin generar una
excepcion Sentry.

Prueba real en produccion: se lanzaron dos sincronizaciones simultaneas; una
respondio que otra ya estaba en curso y la otra termino con `Catalogo
actualizado: 18240 registros procesados.`

### Interpretacion Sentry

- `FARMA-AX` conserva 1 evento historico; no hay un evento posterior al de las
  14:17 UTC en la consulta de 24 horas.
- `FARMA-9E` conserva eventos antiguos de DIGEMID y de
  `inventory:monitor-consistency` agrupados bajo el fingerprint generico de
  scheduler. El ultimo DIGEMID historico fue 07:15 UTC, antes de desactivar el
  job.
- `app/Sentry/BeforeSendCallback.php` agrega fingerprint y tag por comando
  (`scheduled-command` / `scheduled_command`). Los eventos viejos no se
  reagrupan retroactivamente; validar futuros eventos.

## Issues investigados

- `FARMA-AV`: el error era acceso denegado a la base de un tenant. La prueba
  directa de conexion funciono y `inventory:monitor-consistency --tenant=...
  --reset-baseline` termino `CONCILIADO`, con todas las metricas en cero. El
  issue historico puede seguir `unresolved`; eso no prueba una falla actual.
- `FARMA-92`: validacion de presentaciones moviles y codigos de barra duplicados,
  transaccion para update movil e importador de precios protegido antes de
  escribir. Desplegado.
- Reporte de caja: guardia para asociacion nula antes de usar el modelo.
- `FARMA-91`: eager loading de `warehouse_quantities` y lectura desde la
  relacion cargada; elimina la consulta por lote en POS.
- `FARMA-7C`: eager loading de `pricing_states` por almacen y lectura desde la
  relacion; elimina el N+1 de `/pos/tables`.
- `FARMA-9N`: `/documents/records` ya carga `reference_guides` en lote; no se
  observaron eventos nuevos despues de esa correccion.
- `FARMA-8M`: permisos de cache corregidos a `www-data`; los eventos vistos
  fueron anteriores a la correccion, no hay que declararlo resuelto sin volver
  a observar el endpoint.
- `FARMA-8R`: auditoria oficial encontro 330 diferencias de lotes, todas de
  baja confianza. No se ajusto stock automaticamente; requiere validacion
  fisica/documental.
- Seguimiento de Claude: se corrigio el mojibake de los tres mensajes nuevos
  de validacion en `UpdateItemBasicRequest.php` y de la nota de sesion en
  `CLAUDE.md`. Commit `5214fd85`; el request PHP fue copiado a produccion y
  paso `php -l`.

## Commits de esta remediacion

- `8615effb` — validaciones moviles/importador, fingerprint Sentry y guardia de
  caja.
- `20a33251` — batch de estados de precios POS.
- `83c4a9fc` — batch de cantidades de lotes POS.
- `55235d51` — serializacion del sync DIGEMID con lock MariaDB.
- `3cdcb1ad` — documentacion operativa de FPM/Nginx.

## Regla critica de despliegue

Recrear `fpm_softlte_org_pe` cambia su IP interna. Nginx puede conservar la IP
vieja y devolver 502 a todos los tenants. Despues de cualquier
`--force-recreate fpm`, ejecutar:

```bash
docker exec nginx_softlte_org_pe nginx -t
docker exec nginx_softlte_org_pe nginx -s reload
```

Luego verificar logs de FPM, un `/login` HTTPS real y ausencia de `502` o
`connect() failed` en Nginx.

## Como validar de nuevo

1. Buscar en Sentry `digemid` con ventana de 24 horas y revisar timestamps,
   no solo el contador del issue.
2. Revisar `schedule:list`: DIGEMID debe estar ausente mientras la variable sea
   `false`.
3. Confirmar el catalogo y ejecutar una sola sincronizacion manual si hace
   falta; nunca lanzar dos sin comprobar el lock.
4. Para cada N+1, comparar eventos posteriores al deploy; Sentry no reagrupa
   eventos antiguos.
5. Mantener separados los issues historicos sin nuevos eventos de los issues
   que sigan generando eventos actuales.
