CHEFMANAGER IA 3.7.0 · VALIDACIÓN DE ENTREGA (FOOD COURT FASE 1)
==================================================================

Esta validación, a diferencia de docs/VALIDACION-3.6.1.txt (corregida más abajo
en este mismo historial), se hizo ejecutando código real con PHP + PDO_SQLITE
contra una base nueva, no solo con verificación estática. El entorno de
construcción sí incluye el binario PHP en esta ocasión.

RESULTADOS

- php -l sobre los 55 archivos PHP del paquete (54 + FoodCourtService.php
  nuevo): sin errores de sintaxis.
- Instalación SQLite nueva ejecutando Database::connection() de verdad:
  conecta sin errores, PRAGMA integrity_check=ok, 0 violaciones de llaves
  foráneas, 174 tablas (171 de la base 3.6.1 + food_courts,
  food_court_operators, food_court_managers).
- Migración sqlite-v19-food-court.sql: aditiva, no falla sobre una base que
  ya tiene la 3.6.1 completa.

PRUEBA FUNCIONAL DE EXTREMO A EXTREMO (llamando FoodCourtService::dispatch y
la acción pública food-court directamente, con sesiones reales en
user_sessions, no simulacros)

1. Un usuario superadmin crea el patio "Patio Sur" → 201, slug y código
   públicos generados automáticamente y únicos.
2. Listado de patios como plataforma: aparece con operators_count=0.
3. El superadmin invita a la sucursal principal de un negocio existente
   ("Pollos A") → fila food_court_operators en estado pending.
4. El detalle del patio (como plataforma) muestra la operadora en pending.
5. El dueño de "Pollos A" (permiso food_court.manage, sin ningún permiso de
   plataforma) acepta la invitación → pending pasa a active, joined_at se
   completa, responded_by queda registrado.
6. El mismo dueño intenta ponerse a sí mismo en estado "suspended" → rechazado
   con 422 ("No puedes cambiar el estado de tu participación a ese valor").
   Confirma que la sanción de suspensión es exclusiva del administrador del
   patio o del Control Center, no autoservicio.
7. Con un producto y categoría reales publicados por "Pollos A", la acción
   pública food-court devuelve el patio, la operadora con su open_state
   (calculado con la misma lógica de horarios que la acción "menu"), la
   categoría y el producto agregado con precio, operator_id y operator_name.
8. La misma acción pública filtrada por category="Bebidas" (que no existe
   para ese negocio) devuelve 0 productos; filtrada por el código público del
   patio + category="Pollos" devuelve el producto esperado.
9. El dueño de "Pollos A" abandona el patio (status=removed) → la acción
   pública food-court deja de listar esa operadora y sus productos
   inmediatamente (0 operadores, 0 productos), confirmando que el catálogo
   agregado solo refleja membresías activas y visibles en tiempo real.

Lo anterior confirma que el aislamiento multi-tenant se mantiene: en ningún
paso un negocio pudo leer o modificar una fila de food_court_operators que no
fuera la suya, y el catálogo público nunca expuso datos de un operador
pendiente o retirado.

NO CUBIERTO POR ESTA VALIDACIÓN

- El sub-recurso de administradores acotados del patio (food_court_managers:
  asignar/retirar un administrador limitado a un solo food_court) se revisó
  por lectura de código siguiendo el mismo patrón ya probado de
  isFullManager/isCourtManager, pero no se ejecutó un caso de prueba dedicado.
- No hay interfaz de usuario que probar en esta fase (ver docs/RELEASE-3.7.0.txt).
- Falta una prueba HTTP real (curl/navegador) contra un servidor PHP con
  extensión sqlite habilitada en el hosting final; esta validación llamó a
  las clases PHP directamente en CLI, no a través de un servidor web.
