Appearance
Escenarios de validación
Documento migrado desde
franmc01/ninaku-core-api.
Estado: existe cobertura nativa focalizada para Reference, FX, Contabilidad y la fundación multi-business descrita abajo. El resto de escenarios continúa PENDIENTE. La instalación limpia tiene un gate automatizado; su alcance y resultado están en INSTALLATION_RESULT.md. El gate no completa por sí solo DB01 (seguridad/roles/funciones de negocio) ni DB02 (inyección de fallos).
Las pruebas de RLS, triggers, constraints diferidas, concurrencia y precisión necesitan PostgreSQL real con la major elegida. SQLite o mocks no sustituyen esas pruebas; SQLite valida por separado persistencia/replay del cliente. No crear una API CRUD por tabla para obtener cobertura.
Datos mínimos de prueba
Dos organizaciones A/B con identidades y membresías válidas; A tiene dos outlets y dos ubicaciones bajo una entidad legal, B una ubicación. Una variante comercial corresponde a un item de stock directo. Moneda, unidad y configuración explícitas. Las capacidades mínimas se declaran sin precios inventados de producto. Los fixtures no desactivan RLS/triggers para hacer funcionar los flujos.
Escenarios con resultado esperado
| ID | Preparación y acción | Resultado que demuestra corrección |
|---|---|---|
| DB01 | Instalar baseline en BD vacía de versión fijada | Finaliza sin errores; verificar tablas/funciones/constraints/políticas y roles reales. Comparar catálogo, no solo exit code |
| DB02 | Fallar intencionalmente un paso de instalación | Reportar prefijo aplicado y sufijo pendiente; no declarar instalación completa ni conceder runtime |
| SEC01 | A consulta y escribe con IDs pertenecientes a B usando rol runtime | No lee datos de B y no crea enlaces cruzados; usar errores sin filtrar información sensible |
| SEC02 | Alternar A/B en una conexión reutilizada; fallar en medio | No queda contexto del tenant anterior; rollback y nueva petición funcionan |
| SEC03 | Membresía terminada, scope de otro outlet y deny de capacidad | Cada operación se rechaza por el contrato correcto; RLS no sustituye permiso |
| CORE01 | Bootstrap y onboarding inicial; repetir/interrumpir cada fase | Un tenant coherente; mismo comando retoma; payload distinto con misma clave se rechaza; código ajeno no permite apropiación |
| INV01 | Recibir 10 en almacén; despachar 4; recibir 4 en tienda; vender 2 | Almacén 6, tienda 2, tránsito 0, total físico 8 |
| INV02 | Repetir INV01 recibiendo solo 3 | Antes de resolver diferencia: almacén 6, tienda 1 tras vender 2, tránsito 1, total 8. Declarar pérdida luego produce 7, con evidencia |
| INV03 | Saldo utilizable 1; dos conexiones intentan reservar/consumir 1 | Bajo política estricta solo una obtiene capacidad; la otra recibe conflicto. No se prueba secuencialmente |
| INV04 | Item con incremento y unidad; usar en borrador, intentar cambiarlos | Rechazo tras uso persistido; rollback no deja marcador. Casos ON CONFLICT y mismo statement no fabrican ni omiten historial |
| INV05 | Contar mientras hay salida posterior al punto de corte | Ajuste conserva venta concurrente; rechaza conteo sin interpretación temporal definida |
| INV06 | Aplicar reverso y corrección de costo | Cantidad y valoración cambian solo por sus consecuencias; historial previo permanece |
| INV07 | Reconstruir saldos desde movimientos/reservas bajo snapshot consistente | Igualdad con estado operativo; diferencias detectadas y nunca ocultadas por overwrite |
| SALE01 | Venta directa retail con cocina y salón ausentes | Venta y cobro funcionan sin filas ficticias de restaurante; validar instalación mínima además de feature flags |
| REST01 | Venta para llevar sin mesa; luego venta en mesa con comanda | Mismos módulos comerciales; atención/cocina opcionales. Dividir cuenta no duplica líneas ni preparación |
| TX01 | Fallar tras escribir venta pero antes de outbox | Rollback de ambos. Commit confirmado con respuesta perdida y replay devuelve resultado original |
| OFF01 | Aplicar venta/efectivo local y encolar atómicamente; reiniciar cliente | Se conserva operación/cola; no queda efecto local sin comando ni comando aceptado sin efecto |
| OFF02 | Replay de venta dos veces, simultáneo y después de respuesta perdida | Una venta, un efecto de pago, un consumo; misma clave con contenido distinto produce conflicto explícito |
| OFF03 | Cambiar receta/precio entre operación offline y replay | No se reinterpreta silenciosamente lo ocurrido; aceptación o conciliación según versión/política |
| OFF04 | Asignar capacidad 6/4; ambos dispositivos gastan al máximo | Total no excede 10; no reutilizar capacidad por mera expiración si hay consumo sin reconciliar |
| OFF05 | Revocar miembro durante desconexión y recibir efectivo registrado | No ampliar autoridad; preservar evidencia y dirigir revisión según contrato, sin borrar el hecho físico |
| OFF06 | Bootstrap concurrente con commits fuera de orden y reconexión | Ningún evento confirmado se pierde por cursor MAX(id); ack tras persistencia; rebootstrap conserva comandos pendientes |
| PRINT01 | Imprimir offline; sincronizar reporte de éxito repetido | Cero nuevas impresiones por replay; fallo entre envío y confirmación queda como resultado incierto |
| B2B01 | A emite compra, B acepta venta, mensajes repetidos/fuera de orden | Cada tenant tiene sus documentos; deduplicación y correlación; el emisor no escribe como receptor |
| B2B02 | Revocar acuerdo; intentar compartir costos/clientes no autorizados | Bloquea nuevos mensajes fuera de alcance; evidencia previa se preserva y cada tenant ve lo permitido |
| B2B03 | Pedido en cajas, envío parcial y recepción en unidades | Mapeo aceptado 1 caja=12; diferencias visibles, sin confundir SKU de A/B ni confirmar por despacho |
| REC01 | Dump y restore en BD distinta con roles/procedimiento explícitos | Verificar datos, constraints, roles/grants aplicables y RLS después; no confundir copia lógica con PITR |
| PERF01 | Ejecutar consultas y escrituras críticas con tamaño representativo | Registrar EXPLAIN/BUFFERS, latencias, esperas y throughput. Acordar carga/presupuesto antes de fijar objetivos |
Concurrencia y fallos
Usar barreras y dos conexiones reales para controlar el intercalado, no sleeps arbitrarios. Identificar punto de bloqueo, error esperado y resultado persistido. Validar reintentos de la transacción completa solo cuando el comando sea replay-safe. Fallos de permisos o negocio no se reintentan automáticamente.
Evidencia por ejecución
Registrar commit, manifest/hash, versión de PostgreSQL/cliente, rol efectivo, escenario, parámetros de carga no sensibles, resultado, duración y limitaciones. No subir credenciales, volcados con datos reales ni contexto personal de clientes. El conjunto de pruebas inicial debe demostrar los riesgos concretos, no espejar cada CREATE TABLE con una prueba de existencia.
Evidencia de fundación multi-business — revisión 5
business_foundation_fixture.sql construye una Organization con Restaurant y Hotel, un Site compartido, dos Legal Entities, tres Business Units y una BU con dos Verticales. business_foundation_contracts.sql prueba aislamiento por scope, reasignación histórica, contexto vendedor de Sales, Payment→Cash/Treasury y replay offline con evidencia Sync. provisioning_concurrency.py controla dos conexiones reales y demuestra que dos reservas simultáneas con la misma clave convergen en una sola solicitud.
Marcadores esperados: NINAKU_BUSINESS_FOUNDATION_CONTRACTS_OK y NINAKU_PROVISIONING_CONCURRENCY_OK. El resultado pertenece al workflow del commit que los ejecuta; la existencia de los archivos no equivale a PASS.
Refinamiento de Reference/Treasury
La revisión 3 implementa pruebas nativas concretas de conversión y concurrencia, descritas en REFINEMENT_03.md. No equivale a completar INV03, TX01 ni OFF02: sus dominios y transportes son distintos. Los resultados se vinculan al commit del workflow.