Carmen LabsCarmen Labs
MView Experimental · AI first

Entrada operativa para agentes que crean MViews.

Esta especificación es experimental y puede cambiar mientras se valida con implementaciones reales.

Roadmap de MView Experimental

Fases, entregables y criterios para validar MView Experimental de principio a fin.

Roadmap de MView Experimental

Propósito

Este roadmap ordena la implementación y validación de la especificación Experimental. Cada fase debe probarse con artefactos ejecutables antes de congelar su contrato.

El trabajo prioriza dos resultados simultáneos:

  • Robustez para runtimes: contratos completos, validables y seguros.
  • Simplicidad para agentes: pocas decisiones, adapters reutilizables y ejemplos copiables.

Principios de ejecución

  • Cerrar semántica antes de modificar el schema.
  • Implementar primero el camino mínimo completo, no todas las capacidades.
  • Probar contratos con al menos dos implementaciones independientes cuando afecten interoperabilidad.
  • Tratar ejemplos y fixtures como productos de primera clase.
  • No publicar una guía para agentes hasta que sus pasos puedan ejecutarse de extremo a extremo.
  • No declarar estable un identificador de adapter o renderer sin pruebas de conformidad.

Fase 0: decisiones de diseño

Objetivo

Eliminar ambigüedades que cambiarían el schema o el comportamiento observable.

Decisiones

  • Nombre definitivo de source.input o source.capability.
  • Identidad y versionado de adapters registrados.
  • Identidad y versionado de renderers.
  • Ubicación y merge de settings.
  • Recursos compartidos frente a recursos por vista.
  • Forma exacta de filesystem.
  • Contextos mínimos entregados a adapter, transform y render.
  • Política mínima del renderer HTML: scripts, CSP, sandbox y red.
  • Reglas de unicidad para views[].id y versionado del paquete.

Decisiones tomadas

DecisiónOpción elegidaAlternativa rechazadaMotivo
Nombre del campo de capacidadinput en el manifiesto (source.input, source.files[].input, view no aplica)source.capabilityinput ya era el nombre usado consistentemente en manifiesto, runtime (engine.js) y prosa; renombrar no aportaba claridad y hubiera roto la implementación existente sin beneficio.
Forma exacta de filesystem / fuente de directoriosource.files[] explícito: { path, adapter, input, contentHash? }, sin descubrimiento implícitosource.mapping[] por extensión de archivo (lo que tenía mview.schema.json)engine.js y viewer.js ya implementaban y probaban source.files; mapping no estaba implementado en ningún lado y, siendo dispatch implícito por extensión sobre lo que exista en el directorio, contradice directamente la garantía de seguridad "el runtime lee únicamente los archivos declarados, sin descubrimiento". El schema era el que estaba desalineado, no el runtime ni la prosa.
contentHash agregado para directorioDefinido explícitamente: sha256(JSON.stringify(files ordenados por path, cada uno como {path, contentHash})), tal como ya lo calcula engine.jsSerialización canónica RFC 8785La spec Experimental prioriza simplicidad de implementación sobre interoperabilidad estricta entre lenguajes; documentar exactamente lo que el runtime de referencia ya hace evita divergencia entre spec e implementación. Puede revisarse más adelante si la interoperabilidad estricta entre lenguajes se vuelve un requisito real.
Identidad y versionado de adaptersIDs de string estables (csv-table, json-value, markdown-text, plain-text), sin campo de versión propio en el manifiesto; un cambio incompatible requiere nuevo IDVersionado semántico por adapter (csv-table@2)No hay todavía necesidad demostrada de múltiples versiones activas de un mismo adapter; agregar versionado ahora es especular. Ya documentado en la prosa ("Un cambio incompatible requiere otro identificador").
Identidad de renderersÚnico valor soportado en esta versión inicial: "html" (ya reflejado como const en el schema)Enum abierto con múltiples renderers desde el inicioCoincide con el alcance real implementado en viewer.js. Se documenta explícitamente como limitación de esta versión, no como diseño cerrado para siempre.
Recursos compartidos vs por vistaSolo view.resources (por vista)mview.json-level resources compartido entre vistasEs lo único implementado y probado en viewer.js (/resources/<viewId>/...). Recursos compartidos quedan fuera de alcance de este cierre; se puede añadir como campo opcional más adelante sin romper manifiestos existentes.
Merge de settingsPackage → view → overrides de runtime, shallow merge, sin merge recursivoMerge profundo (deep merge)Ya documentado y ya implementado ({ ...manifest.settings, ...view.settings } en engine.js); un merge profundo agrega ambigüedad sin caso de uso probado.
Contexto mínimo del transform{ source, settings, view, manifest } — se agrega manifest (id, name, description, version, source, settings, metadata) a lo ya documentadoMantener el contexto sin manifestengine.js ya entrega context.manifest; la prosa no lo documentaba. Se documenta el comportamiento real en vez de eliminar código funcional.
Política del renderer HTMLNormativa: inyección de window.mview antes de scripts inline, ejecución en iframe sandbox="allow-scripts" (sin allow-same-origin ni allow-forms), CSP connect-src 'none' en el documento renderizado, servidor de referencia enlazado solo a 127.0.0.1, refresh autenticado con token efímero de sesiónDejar la política como no-normativa/orientativaviewer.js ya implementa exactamente esto; convertirlo en contrato normativo evita que otras implementaciones bajen el nivel de seguridad.
Unicidad de views[].id y source.files[].pathMUST explícito en la prosa + validación semántica obligatoria fuera de JSON Schema (JSON Schema no puede expresar unicidad por clave dentro de un array de objetos)Confiar en uniqueItems de JSON SchemauniqueItems compara igualdad estructural completa, no por clave; ya se necesitaba (y ya existía en engine.js) un validador semántico adicional. Se documenta como requisito explícito de cualquier implementación conforme.

Entregables

  • Registro breve de decisiones con una opción elegida y alternativas rechazadas.
  • Manifiestos para archivo, directorio, una vista y varias vistas.
  • Tipos TypeScript de todas las formas normalizadas y contextos.

Criterio de salida

Ninguna decisión pendiente afecta campos requeridos, formas normalizadas o límites de seguridad.

Nota sobre el entregable "manifiestos para archivo, directorio, una vista y varias vistas"

Las cuatro combinaciones existen implícitamente pero no las cuatro como ejemplos independientes: archivo+una vista y archivo+varias vistas están en examples/csv/ (Ejemplo 1 y Ejemplo 2); directorio+una vista está en examples/directory/. Directorio+varias vistas no tiene un ejemplo dedicado — no hay nada en el schema o el runtime que lo restrinja (views[] no depende de source.kind), es exactamente el mismo patrón de "agregar otra entrada a views[]" que ya demuestra Ejemplo 2 sobre una fuente de archivo. Se considera cubierto por combinación de ejemplos existentes, no por un caso separado.

Fase 1: contrato machine-readable

Objetivo

Mantener un único schema Experimental estricto.

Trabajo

  • Mantener el modelo de una fuente y views[].
  • Usar https://carmenlabs.com/experimental/schema.json como identidad durante toda la evaluación.
  • Definir condicionales para fuentes de archivo y directorio.
  • Validar paths de paquete y paths relativos a directorio.
  • Rechazar propiedades desconocidas.
  • Añadir validaciones semánticas que JSON Schema no expresa, especialmente unicidad de views[].id y escapes mediante symlinks.
  • Crear fixtures válidos e inválidos para cada regla.

Entregables

  • mview.schema.json definitivo.
  • Validador semántico complementario.
  • Corpus de manifests válidos e inválidos.
  • Pruebas automatizadas de schema y paths.

Criterio de salida

Todos los manifests del catálogo de ejemplos validan y cada fixture inválido falla por la razón esperada.

Estado: cumplido

Los 7 manifests de ejemplo validan contra mview.schema.json (verificado ejecutando validateManifest contra cada uno, no solo revisando a simple vista). El corpus de fixtures inválidos vive inline en los tests en vez de como archivos .json separados — test/directory-source.test.js y test/security-anti-examples.test.js cubren: fuente de directorio sin files, files duplicados, views[].id duplicados, contentHash que no coincide (agregado y por archivo), y escapes de ruta — cada uno con la aserción de por qué falla. El validador semántico complementario es validateManifest en engine.js (unicidad de IDs, compatibilidad adapter/input) más resolveContainedPath (escapes vía .. y symlinks).

Fase 2: contratos normativos

Objetivo

Documentar las garantías que permiten implementaciones portables y seguras sin inflar el manifiesto.

Trabajo

  • Actualizar overview y referencia del schema.
  • Reemplazar parser/component por transform/render donde corresponda.
  • Especificar Source Adapter, registro, capacidad de salida y cache.
  • Especificar serialización, determinismo y mutabilidad de entradas.
  • Definir refresh y regeneración como operaciones distintas.
  • Definir errores globales de fuente y errores aislados por vista.
  • Completar seguridad, paths, red, symlinks y directorios.
  • Sincronizar documentación en español e inglés.

Entregables

  • Especificación completa en ambos idiomas.
  • Matriz de requisitos MUST, MUST NOT y SHOULD por actor.
  • Diagrama normativo del ciclo de refresh.

Criterio de salida

Un implementador puede construir un runtime sin depender de comportamiento implícito en los ejemplos.

Estado: parcialmente cumplido

unified-mview.md documenta parser/transform/render, Source Adapter y registro, serialización y determinismo, refresh vs. regeneración como operaciones distintas (con diagrama del ciclo de refresh), y seguridad/paths/symlinks/directorios completos, incluyendo una sección dedicada a validaciones semánticas que el JSON Schema no puede expresar. La matriz MUST/MUST NOT/SHOULD por actor no existe como tabla separada — está distribuida como listas de reglas dentro de cada sección (Source Adapters, Transform, Render, Seguridad); se considera equivalente en contenido, no en formato. Pendiente real: sincronizar documentación en español e inglés — se decidió diferir la traducción a inglés hasta que el contenido esté completamente estable, para no traducir contenido que todavía podía cambiar dos veces.

Fase 3: adapters de referencia

Objetivo

Eliminar la generación repetitiva de parsers físicos para formatos comunes.

Alcance inicial

AdapterEntradaFormaLímites explícitos
csv-tableCSV UTF-8tableRFC 4180 básico, comillas y saltos de línea documentados
json-valueJSON UTF-8valueJSON estricto, sin JSON5
markdown-textMarkdown UTF-8markdowntexto y headings, sin ejecutar HTML
plain-texttexto UTF-8textpolítica explícita para BOM y UTF-8 inválido

Trabajo

  • Extraer adapters fuera de paquetes particulares.
  • Definir metadata de registro y capacidad producida.
  • Añadir fixtures pequeños y casos límite.
  • Probar determinismo y errores legibles.
  • Probar invalidación por cambio de bytes, opciones y versión.

Entregables

  • Directorio mview/reference/adapters/ o ubicación definitiva equivalente.
  • Un módulo, README, fixtures y tests por adapter.
  • API de registro mínima para runtimes.

Ubicación definitiva (decidido)

Los cuatro adapters viven en carmenlabs.com/public/experimental/adapters/*.mjs, servidos como archivos estáticos en /experimental/adapters/*.mjs (los enlazan unified-mview.md y llms.txt). mview/viewer los importa directamente desde ahí. Se descarta moverlos a mview/reference/adapters/: duplicaría el módulo servido públicamente y crearía dos fuentes de verdad para el mismo código. El registro mínimo de runtime (id, input, adapt) vive en mview/viewer/src/adapters.js, y sus fixtures y tests de determinismo/errores están en mview/viewer/test/adapters.test.js (32 casos, uno por adapter más los cuatro formatos y sus límites explícitos de la tabla de alcance inicial).

Criterio de salida

Los cuatro formatos del alcance inicial pueden usarse sin copiar adapters al paquete ni generar código de parseo físico. ✅ Cumplido: cada adapter tiene pruebas de determinismo, encoding inválido y forma normalizada específica.

Fase 4: runtime y renderer de referencia

Objetivo

Ofrecer un camino ejecutable común para probar paquetes y renders HTML.

Trabajo

  • Implementar el pipeline validate → read → adapt → transform → render.
  • Compartir una adaptación entre varias vistas.
  • Entregar props de forma consistente.
  • Aislar fallos por vista.
  • Restringir filesystem y red.
  • Definir inyección segura de window.mview y política de contenido.
  • Exponer refresh sin escritura del paquete.

Entregables

  • Runtime o biblioteca mínima de referencia.
  • Renderer HTML de referencia.
  • Reporte estructurado de errores por fase y vista.
  • Pruebas de refresh, aislamiento y seguridad.

Criterio de salida

El runtime ejecuta todos los ejemplos y demuestra que una fuente se adapta una sola vez por refresh.

Estado: cumplido

mview/viewer implementa el pipeline completo (validate → read → adapt → transform → render), comparte una única adaptación entre varias vistas (test/viewer.test.js — "adapts the source exactly once per package refresh"), entrega props consistentes ({ data, settings, source, view, resources }), aísla fallos por vista, restringe filesystem/red en el transform (proceso separado, permisos acotados, sin globals de Node) y en el render (iframe sandbox + CSP), inyecta window.mview de forma segura, y expone refresh sin escribir el paquete (/api/refresh, autenticado con token efímero). Ejecuta los 7 ejemplos y los ejemplos de directorio confirman además que un archivo no seleccionado nunca se lee.

Fase 5: paquetes de ejemplo

Objetivo

Dar a agentes patrones completos que puedan copiar con cambios locales mínimos.

Ejemplos mínimos

  1. CSV con una vista HTML.
  2. CSV con dos vistas independientes.
  3. JSON con una vista HTML.
  4. Markdown con tabla de contenidos y resumen.
  5. Texto con métricas simples.
  6. Directorio con selección explícita y entradas heterogéneas.
  7. Vista que falla sin impedir otra vista válida.

Requisitos por ejemplo

  • Fuente real pequeña.
  • mview.json válido.
  • Transform determinista.
  • Render sin dependencias innecesarias.
  • Snapshot o assertions del modelo derivado.
  • Prueba de refresh sobre copia temporal.
  • README con “qué copiar” y “qué reemplazar”.

Criterio de salida

Un agente puede crear una MView nueva seleccionando el ejemplo más cercano y modificando únicamente manifiesto, transform y presentación.

Estado: cumplido

Los 7 ejemplos mínimos están implementados bajo mview/viewer/examples/, cada uno con README.md, fuente real, <paquete>.mview/, expected/data.json (generado ejecutando el pipeline real, no a mano) y test.mjs:

#PatrónCarpeta
1 y 2CSV con una vista / CSV con dos vistasexamples/csv/ (pokemons-data.mview, vistas stats + pokedex)
3JSON estructuradoexamples/json/
4Markdownexamples/markdown/
5Texto planoexamples/text/
6Directorio explícitoexamples/directory/ — además prueba que un archivo no declarado en source.files (march.csv) se ignora aunque exista físicamente
7Vista que falla junto a otra válidaexamples/failing-view/

test.mjs de cada ejemplo sigue el procedimiento de 8 pasos de "Qué debe contener cada ejemplo implementado" vía el runner compartido examples/lib/example-runner.mjs (excepto failing-view, que lo implementa a mano porque una de sus vistas falla por diseño). Construir estos ejemplos encontró y corrigió un bug real en transform-runner.js: los errores lanzados dentro del vm.Context del transform no son instanceof Error en el realm del host, así que el manejo de errores caía a String(error) y anteponía "Error: " a todo mensaje de fallo de un transform. Corregido con verificación por duck-typing (typeof error.message === "string").

Fase 6: experiencia para agentes

Objetivo

Reducir la creación normal a una guía corta y verificable.

Trabajo

  • Reescribir la página canónica de creación para seleccionar adapter y ejemplo antes de generar código.
  • Publicar una tabla “tipo de fuente → adapter → ejemplo”.
  • Entregar templates de transform y render HTML.
  • Añadir checklist automático de terminado.
  • Prohibir explícitamente reimplementar adapters disponibles.
  • Hacer que la instrucción inicial cree una sola vista salvo solicitud contraria.

Entregables

  • Guía canónica para agentes.
  • Skill opcional alineada con la misma guía.
  • Prompt mínimo probado con distintos modelos.
  • Evaluación de tasa de éxito y cantidad de archivos/código generado.

Métricas sugeridas

  • Porcentaje de manifests válidos al primer intento.
  • Porcentaje de campos inventados respecto de la fuente.
  • Líneas de código generadas fuera de transform y render.
  • Porcentaje de tareas que reutilizan el adapter correcto.
  • Porcentaje de refreshes exitosos después de cambiar la fuente.
  • Porcentaje de paquetes que respetan aislamiento de E/S.

Criterio de salida

La mayoría de los modelos evaluados crea el paquete correcto sin generar un adapter ni modificar la fuente.

Fase 7: congelamiento de Experimental

Objetivo

Congelar un contrato Experimental coherente respaldado por implementaciones y pruebas.

Checklist

  • Schema, documentación y ejemplos coinciden.
  • Español e inglés están sincronizados. — diferido a propósito hasta que el contenido esté estable (ver Fase 2).
  • Todos los links y rutas públicas funcionan. — verificado con curl contra el dev server real, no solo revisando el markdown fuente.
  • Todos los ejemplos pasan schema, runtime y refresh. — pnpm test en mview/viewer, 63/63.
  • Los adapters del alcance inicial tienen identificadores estables.
  • El renderer HTML cumple la política de seguridad acordada.
  • Las fuentes de directorio tienen pruebas de escapes y symlinks.
  • Los fallos por vista están aislados.
  • No quedan rutas, ejemplos o recursos obsoletos bajo /experimental. — se eliminó carmenlabs.com/experimental/adapters/ (directorio vacío sin referencias). Quedan app/experimental/viewer/ y app/experimental/specification/: dos carpetas de ruta vacías (sin page.tsx ni route.ts, devuelven 404) que no sirven contenido bajo /experimental — no rompen el checklist, pero conviene borrarlas o poblarlas; decisión pendiente del autor.
  • /experimental/schema.json entrega el schema congelado. — verificado en vivo: directorySource.required incluye files, no existe mapping.

Estado: cerrado con una excepción conocida

Experimental está congelado y coherente en todo lo que sirve /experimental, con una sola excepción explícita y deliberada: la sincronización español/inglés. Ninguna otra casilla quedó sin verificar contra el estado real del repo — no contra lo que debería estar, sino releyendo cada documento, revalidando cada manifiesto de ejemplo, y confirmando cada ruta pública con una petición HTTP real.

Criterio de salida

Existe una sola interpretación de MView Experimental y el camino recomendado para agentes está respaldado por implementaciones y pruebas reales.

Orden crítico

decisiones
    |
    v
schema + tipos
    |
    v
contratos normativos
    |
    +----------------+
    v                v
adapters         runtime/renderer
    |                |
    +-------+--------+
            v
         ejemplos
            |
            v
    guía para agentes
            |
            v
 congelar Experimental

Los ejemplos pueden bosquejarse durante las primeras fases, pero no deben presentarse como canónicos hasta que schema, adapters y runtime los validen.