face_verification_core 0.2.0

Cross-platform on-device face liveness and verification core.
Documentation
# Contexto Para Retomar El Proyecto

Este proyecto nace de `naru_verify_web`, una web Vite cliente que ya prueba el
flujo de verificación facial con `face-api.js`, `nsfwjs`, TFJS y Supabase.

La web provisional tiene tres modos:

- `mode=verify`: captura 6 fotos y guarda embedding solo al pasar todo.
- `mode=recovery`: busca una cuenta por cara.
- `mode=moderate`: valida NSFW y match facial para fotos de perfil.

La arquitectura web funciona para validar producto rápido, pero no es ideal a
largo plazo:

- El JavaScript cliente es público y manipulable.
- La UX abre navegador/webview.
- El retorno automático a escritorio no es fiable; la app Flutter debe hacer
  polling al volver.
- Si hay token/recompensas cripto, aprobar desde código cliente no es una raíz
  de confianza suficiente.

La decisión para este repo es separar la lógica reusable en Rust:

- `face_verification_core`: core Rust puro y reusable.
- `face_liveness_kit`: paquete Flutter/pub.dev con UI, cámara y puente.

## Estado Actual

El crate ya contiene la lógica determinista de liveness y verificación final:

- generación de challenge de 6 pasos,
- validación de poses por frame,
- sesión con estabilidad temporal,
- validación final de 6 fotos,
- rechazo por duplicados,
- comparación de embeddings,
- API JSON para consumo desde Flutter/Rust bridge.

También se añadió la base para runtime ML nativo:

- `ModelBundle` y `ModelAsset`,
- roles de modelo (`FaceDetector`, `FaceLandmarks`, `FaceEmbedding`,
  `FaceExpression`, `HandLandmarks`, `Age`, `Nsfw`),
- formato `Onnx`,
- feature opcional `runtime-tract`,
- validación de bytes ONNX mediante `tract` cuando la feature está activa,
- `FaceVerificationEngine` como punto de entrada headless futuro.

La versión local está preparada como `0.2.0`. La versión `0.1.0` ya fue
publicada en crates.io y no incluye todavía el runtime/contrato de modelos.

La inferencia real todavía no está implementada: `analyze_image` valida entrada
y presencia de modelos requeridos, pero devuelve `NotImplemented` hasta añadir
preprocesado, ejecución del grafo y postprocesado por modelo.

## Decisión De Modelos

No hay modelos incluidos en el crate por ahora. Esto evita bloquear el avance por
licencias. El diseño actual permite que la app o un paquete posterior pase los
pesos ONNX que se decidan usar.

Ruta elegida:

1. Empezar con ONNX + `tract`.
2. Probar detector, landmarks y embeddings con licencias compatibles.
3. Si `tract` no soporta una operación necesaria, evaluar fork/mejora de
   `tract` antes de cambiar de runtime.
4. Mantener `ort` como alternativa solo si `tract` no encaja por soporte o
   rendimiento.

## Reglas De Producto Importantes

- Solo se bloquean duplicados activos: una persona no puede tener dos cuentas
  activas a la vez.
- Si un usuario borra voluntariamente su cuenta, se borran sus embeddings y
  puede registrarse con otro email inmediatamente.
- Un bloqueo administrativo futuro puede conservar identidad bloqueada, pero
  ese caso debe ser distinto de borrar cuenta voluntariamente.
- El embedding no debe guardarse si no se completa todo el challenge.

## Pipeline Actual A Replicar

1. Mostrar instrucción.
2. Esperar al menos 2 segundos antes de permitir auto-captura.
3. Validar continuamente cara + gesto.
4. Capturar solo si el gesto correcto se mantiene estable unos 2 segundos.
5. Permitir captura manual como fallback, pero siempre pasar por validación.
6. Reanalizar las 6 fotos al final antes de devolver embedding.

Challenge actual:

1. Cara centrada.
2. Sonrisa.
3. Giro hacia flecha izquierda en pantalla.
4. Giro hacia flecha derecha en pantalla.
5. Mostrar N dedos.
6. Tocar nariz, mejilla u oreja.

## Mensajes UX Deseados

- Centra tu cara en el óvalo.
- Sonríe más.
- Gira más hacia la flecha.
- Muestra N dedos.
- Acerca el dedo a la nariz/mejilla/oreja.
- Cargando detector de manos.

## Referencias Locales

- Web provisional de producto: `naru_verify_web`
- Flutter app Naru actual: `naru_chatgpt`
- Plan viejo mas Naru-especifico: `naru_face_verify`