Anunciarse en NOalergeNO
Arquitectura de publicidad
El cortafuegos, y por qué es real
La separación entre motor de seguridad y motor comercial no es una política que alguien pueda saltarse con una prisa un viernes. Está sostenida por tres mecanismos independientes:
1. Grafo de dependencias. apps/pwa/js/anuncios.js no importa nada de packages/motor. No es que no lo use: es que no puede.
grep -r "packages/motor\|@noalergeno/motor" apps/pwa/js/anuncios.js
# sin resultados
2. Un contexto que se niega a contaminarse. La única entrada del motor comercial es construirContexto(), que lanza una excepción si detecta cualquier campo de salud:
const VETADOS = ['perfil','evita','alergenos','condiciones','salud',
'diagnostico','health_profile','porNo','matriz','resultado'];
Si alguien intenta pasar el perfil, no sale un anuncio peor: no sale anuncio y se registra un error. Fallar en cerrado, no en abierto.
3. Bases de datos distintas. 002_publicidad.sql está escrito para ejecutarse en otra base. No hay ninguna clave foránea del esquema comercial al esquema de personas. Aunque alguien escribiera la consulta, no hay JOIN posible.
Lo que entra al motor comercial
{
categoria: 'galletas',
subcategoria: null,
mercado: 'ES',
idioma: 'es',
productoActual: '8410000810004',
tipoContexto: 'resultado'
}
Eso es todo. Contexto de compra. No hay ni un campo donde quepa una condición de salud, y el esquema de ad_contexts en base de datos tampoco lo tiene.
Lo que se vende
No se vende «audiencia celíaca». Se vende contexto de compra de alta intención:
«Un consumidor está buscando una alternativa en la categoría galletas, en España.»
La diferencia no es de marketing. Es que la primera frase requiere saber que la persona es celíaca, y la segunda no. Una impresión después de un producto incompatible vale más que un banner genérico precisamente porque hay intención, no porque haya un diagnóstico.
Zonas sin publicidad
Nunca, bajo ninguna campaña, ninguna excepción:
- El escáner y la cámara.
- La pantalla de proceso.
- El resultado, su explicación y sus evidencias.
- Información insuficiente e información contradictoria.
- Alertas alimentarias y retiradas.
Está implementado en el motor: compararConPerfil() devuelve zonaSegura: true para contiene, puede, contradictoria, insuficiente y muy_bajo, y pintarResultado() no llama al módulo comercial si zonaSegura es cierto.
Verificado en navegador — ver TESTING.md:
| Resultado | Anuncios en la pantalla |
|---|---|
| CONTIENE | 0 |
| PUEDE CONTENER | 0 |
| INFORMACIÓN CONTRADICTORIA | 0 |
| INFORMACIÓN INSUFICIENTE | 0 |
| DECLARADO SIN | tras el bloque de fuentes |
| NO HEMOS DETECTADO | tras el bloque de fuentes |
Orden de la pantalla
RESULTADO
↓
POR QUÉ
↓
EVIDENCIA
↓
FUENTE
────────── frontera visible ──────────
ALTERNATIVAS (orgánicas, sin pagar)
↓
PATROCINADO
↓
DÓNDE COMPRAR
Nada de la derecha adelanta a nada de la izquierda. Además, el módulo comercial se pinta en un requestAnimationFrame posterior y dentro de un try: no puede retrasar el resultado ni romperlo si falla.
Formatos
Por prioridad de inventario:
1. Alternativa patrocinada — el formato estrella. Aparece cuando la marca puede ofrecer algo relevante, después de un resultado incompatible. 2. Búsqueda patrocinada. 3. Patrocinio de categoría. 4. Colocación de retailer. 5. Cupón. 6. Banner — deliberadamente el último.
Elegibilidad
Una marca no clasifica sus propios alérgenos. Puede aportar datos; la clasificación la determina NOalergeNO.
La marca pide: "quiero anunciar esto como sin gluten"
↓
¿Hay evidencia adecuada?
├── sí → eligible, con la evidencia registrada y una fecha de caducidad
└── no → not_eligible
En ad_eligibility: status, evidence, evidence_source, verified_at, expires_at. Si la evidencia caduca, la campaña se suspende sola. Si aparecen fuentes contradictorias sobre el producto, las campañas afectadas se pausan. Seguridad por encima de ingreso, y automatizado para que no dependa de que alguien se acuerde.
Identificación y transparencia
- Toda publicidad va etiquetada «Patrocinado», con su propia superficie visual (cálida y neutra) y nunca con los colores de la escala semafórica.
- El lector de pantalla la anuncia como publicidad antes de leer su contenido (
aria-label="Publicidad de <marca>"). - «¿Por qué veo este anuncio?» está implementado y responde con el contexto real: «Este anuncio aparece porque estás consultando la categoría galletas en ES. No usamos tu perfil de salud para elegirlo. Paga: <anunciante>.»
ad_transparency_logguarda la creatividad tal como se mostró, el anunciante, quién paga, el contexto y el motivo. Para poder auditarlo años después.
Prohibido
Intersticiales antes del resultado. Vídeos obligatorios. Cuentas atrás. Popups. Anuncios encima del escáner. Autoplay con sonido. Anuncios que parezcan alertas. Anuncios que usen los colores del sistema de seguridad. Dark patterns.
Si no hay nada relevante, no se rellena
Implementado: si no hay candidato para el contexto, no sale anuncio. Sale una frase honesta:
Todavía no tenemos alternativas que ofrecerte para esta categoría. Preferimos no enseñarte nada antes que enseñarte cualquier cosa.
Confianza del usuario por encima de tasa de relleno. Es una decisión económica consciente, no un descuido.
Menores
Los perfiles infantiles los gestiona un adulto. No hay publicidad personalizada para menores. La publicidad contextual se mantiene, porque no usa nada de la persona.