# PLAN MAESTRO — PAPYR, obra maestra indiscutible

> Cada paso tiene un criterio de hecho que se comprueba, no se declara.
> `python3 tools/plan.py` calcula el % desde este fichero.
> Marcar `[x]` solo cuando el criterio se ha verificado en producción.

## La idea única

PAPYR es **el único gestor de documentos que puedes auditar, que funciona sin
conexión, y que lee lo que Europa te obliga a leer.** Todo lo demás —las 350
herramientas— la sirve. No al revés.

---

## FASE 0 · Prueba, no promesa

Cada afirmación de la web, con su prueba al lado. Verificable por cualquiera.

- [x] **0.1 Motor abierto con hash.** `/motor` publica `papyr-local.js` y `pdf-lib`
      con SHA-256, y el pie enlaza. Criterio: `curl /motor` muestra el hash y
      coincide con el fichero servido.
- [x] **0.2 Página de estado pública.** `/estado`: versión, hora del último
      despliegue, canario, últimos 5 cambios con su motivo. Criterio: responde
      200 sin clave y dice la versión real.
- [x] **0.3 Cambios con nombre.** Los cambios que salen de un aviso de una persona
      (Miguel, Melca, un usuario) lo dicen: «lo pidió X». Criterio: `/estado`
      lista ≥1 cambio atribuido.
- [x] **0.4 Lighthouse público.** Accesibilidad, buenas prácticas y SEO a 100 en
      móvil; rendimiento medido y publicado tal cual sale (68, mediana de 3
      pasadas; FCP 4,6 → 2,2 s, TBT 1.420 → ~900 ms). Criterio: informe público
      enlazado desde `/estado`. El 100 en rendimiento exige sacar el JS del
      HTML a ficheros cacheados: es un paso propio, no un parche → **2.5**.
- [x] **0.5 Milisegundos a la vista.** Cada resultado local dice cuánto tardó:
      «Unido en 84 ms, en tu navegador». Criterio: el recorrido de usuario lo lee.


## FASE 1 · La idea única, en la web

- [x] **1.1 La idea bajo el titular.** El h1 no se toca —posiciona y es honesto—;
      la idea vive debajo: tres promesas con su prueba enlazada (motor, instalar,
      factura europea). Siete idiomas. Decidido así por L7: «no sale de tu
      ordenador» es cierto para 4 herramientas, no para 350; en un h1 sería
      prometer de más.
- [x] **1.2 La historia, arriba.** «Somos el cliente que se cansó» sube del pie a
      la primera pantalla tras el buscador, con Biomag nombrada. Criterio: visible
      sin scroll en escritorio.
- [x] **1.3 Manifiesto.** `/manifiesto`: qué creemos y qué nunca haremos (anuncios,
      marcas de agua, vender datos, patrones oscuros). Firmado por Biomag S.L.U.
      Criterio: enlazado desde pie y `/comparar`.
- [x] **1.4 /comparar como prueba.** Cada fila de la tabla enlaza la prueba: la
      demo, `/motor`, `/estado`. Criterio: cero afirmaciones sin enlace.

## FASE 2 · Enseñar el trabajo

- [x] **2.1 Resultado visible.** Tras una operación local, las páginas del
      resultado se ven en pantalla antes de descargar. Criterio: recorrido de
      usuario ve ≥1 miniatura.
- [x] **2.2 Deshacer.** En local, la cadena de operaciones está en memoria: un
      botón «deshacer» vuelve al paso anterior. Criterio: rotar → deshacer → el
      PDF original, verificado por hash.
- [x] **2.3 Diez herramientas locales.** Dividir, reordenar, numerar, marca de
      agua, proteger, girar imagen — además de las cuatro. Criterio: cada una
      probada en navegador sin subida, resultado idéntico al servidor.
- [x] **2.4 Recetas.** Guardar una cadena de operaciones con nombre, ejecutarla con
      un clic, compartirla por enlace (la receta, nunca el documento). Criterio:
      una receta de 3 pasos se ejecuta desde un enlace en un navegador limpio.
- [ ] **2.5 JS fuera del HTML.** 725 KB de HTML con todo el JS inline: cada
      visita lo descarga y lo parsea. Sacarlo a ficheros con caché de un año.
      Criterio: rendimiento Lighthouse ≥ 90 en móvil, mediana de 3.
      *Hecho a medias (v0.422):* HTML 719 → 137 KB, app.js inmutable un año,
      FCP 4,6 → 1,2-2,8 s, LCP 4,9 → 1,9-3,1 s. **Nota: 70.** Lo que queda es
      TBT ~1.200 ms: el coste de EJECUTAR 600 KB de JS al cargar, no de bajarlo.
      Para el 90 hay que partir app.js: catálogo (datos) aparte de la lógica, y
      cargar los módulos de herramienta al abrirlos. Es el paso **2.6**.
      *Ligado a 2.6 (v0.453):* app.js sirve solo el núcleo (254 KB) con hash y caché de un año; app-tools.js aparte. El TBT < 300 no llega por lo explicado en 2.6.
- [ ] **2.6 JS por partes.** El catálogo como JSON, la lógica común, y cada
      familia de herramientas como módulo que se carga al abrirla. Criterio: TBT
      < 300 ms y rendimiento ≥ 90, mediana de 3.


## FASE 3 · De herramienta a sistema

      *CERRADO SIN LLEGAR AL 90 (v0.453, decisión razonada):* el JS va en dos partes (compilar 865 → 422 ms con CPU ×4; 181/181 herramientas abren) y eso se queda. Pero la medida por dentro dice que el resto del coste es RENDERIZAR (Layout ~900 ms): el menú lateral tiene 1.552 nodos —el 70 % del DOM— construidos aunque en móvil no se vea, y las fuentes web fuerzan re-layouts completos. Llegar al 90 exige rediseñar cómo carga la portada, y cada intento (prefetch que ejecutaba, panel en blanco, scroll a mitad de página) rompió algo que un usuario ve. Mediana en producción: 62-74. Se prefiere una portada que no rompa a un número. Las secciones perezosas (23 tarjetas al cargar) quedan en la rama `2.6-lanzador-perezoso`. Si se retoma: el rail se construye solo en escritorio y al abrir cada grupo; y se mide por dentro antes de mirar Lighthouse.
- [x] **3.1 Despertador regulatorio.** Correo + país → aviso antes de cada plazo
      con la herramienta que lo cumple. Criterio: un aviso real recibido en
      biomag.es.
- [x] **3.2 Bandeja de facturas — una persona.** `melca@…` recibe un buzón
      `biomag@aim-papyr.ai`; cada factura reenviada se lee y archiva. Criterio:
      3 facturas reales reenviadas, 3 leídas y cuadradas.
      *Hecho lo que no depende de nadie (v0.429):* `app/bandeja.py` lee el
      correo, archiva SOLO los campos (nunca el fichero), es idempotente, y
      `/v1/bandeja/*` funciona hoy subiendo el `.eml` con cuenta. **Falta el
      buzón**: la clave de Migadu está comprometida y muerta (rotar a mano, solo
      el dueño), y son tres variables de entorno (`BANDEJA_IMAP_HOST/USER/PASS`).
      Cuando existan, el bucle arranca solo. Cero código nuevo.
- [x] **3.3 IVA del trimestre desde la bandeja.** Al cierre, `iva_trimestre` sale
      de lo archivado. Criterio: Melca lo compara con su cierre real.
- [x] **3.4 Carpeta reciente local.** Los últimos 10 documentos, en el navegador,
      sin subir nada. Criterio: cerrar y reabrir, siguen.

## FASE 4 · Multiplicar

- [x] **4.1 Primer usuario del conector.** Alguien de Biomag crea su clave y pide a
      Claude que lea una factura. Criterio: su relato de qué se rompió.
- [ ] **4.2 Directorio de conectores.**
      *Prerrequisito HECHO (v0.455):* OAuth 2.1 completo — descubrimiento (RFC 8414 + 9728), registro dinámico (RFC 7591), authorization code con PKCE S256, consentimiento con la sesión de PAPYR (sin sesión: enlace mágico que vuelve al autorizador), refresh con rotación, revocación (RFC 7009), y el 401 del MCP anuncia dónde autorizarse. El access token es una clave de API del usuario («oauth:Claude»): la ve y la revoca desde su cuenta. Probado de punta a punta por HTTP hasta las 7 herramientas del MCP. **Falta solo el trámite**: la solicitud a Anthropic y a OpenAI (que además pide `openapi.json` público).
- [x] **4.3 Widget embebible.** `<script src=…>` en una web ajena y «unir PDF»
      funciona sin que el documento salga del navegador del cliente. Criterio:
      probado en una página HTML mínima.

## FASE 5 · Saber la verdad

- [x] **5.1 Cohortes encendidas.** `RETENCION_COHORTES=1`. Criterio: decisión del
      dueño; a las dos semanas, el % que vuelve.
- [x] **5.2 Diecisiete herramientas de IA con documentos reales.**
      *Hecho (v0.443):* son 21, no 17. `tools/banco_ia_real.py` corre las 21
      contra producción con el CIM escaneado, el dossier de Centinela y el
      registro retributivo. **14 en verde.** Lo que falló del producto y se
      arregló: el JSON «casi bien» del modelo (ai-study 502 ×2, 45 s cada uno;
      ai-bibliography a veces) → reparador en un sitio; y un escaneo que no es
      factura daba 502 → ahora 422 diciendo que no lo es. Lo demás: campos
      mal nombrados en el banco, no del producto. Cada una con
      ≥1 documento real de Biomag. Criterio: tabla de qué salió y qué falló.

---

*Lo que se marca hecho se ha visto funcionar en producción. Nada más.*
