Contrato de Activación
Cargar cuando el usuario quiera un video con voz que explique una funcionalidad o reproduzca un bug, o cuando las capturas de pantalla por sí solas no puedan mostrar un flujo (tiempo, secuencia, estado que cambia). Para un único estado estático, una captura de pantalla es suficiente: no grabar.
La CLI reside en C:\Users\DESARROLLADORES\Documents\personal\ai-video-evidence (node bin/narrate.mjs). Necesita Node 22+, ffmpeg/ffprobe en PATH, Google Chrome y pip install edge-tts.
Reglas Estrictas
- Escribir el guion primero (
narration.json), validarlo, luego grabar. Nunca grabar y narrar manualmente. - Una escena = una idea y una o dos frases. La voz debe describir lo que está en pantalla en esa escena, nunca lo que viene después.
- El idioma de la narración coincide con la audiencia (Español para PRs de Trip2). Voz por defecto
es-CO-SalomeNeural; masculina:es-CO-GonzaloNeural. - Nunca escribir contraseñas. Para aplicaciones autenticadas, el usuario ejecuta
narate login <url>e inicia sesión; apuntarbrowser.storageStateal archivo guardado. Eliminar ese archivo después de grabar y mantenerlo fuera de git. - Usar solo datos de prueba confirmados por el usuario. Los nuevos registros obtienen un prefijo
QA_; nunca editar ni eliminar registros existentes. - Mantener las salidas fuera de git (
out/,pr-assets/). - Flujos no deterministas (LLM, trabajos asíncronos): verificar el resultado en los fotogramas grabados. Si la aplicación hizo algo diferente a lo que dice la narración, volver a grabar; nunca enviar un video cuya voz contradiga la pantalla.
Puertas de Decisión
| Situación | Acción |
|---|---|
| Reporte de bug | assets/bug-template.json: contexto → pasos → actual (llamada roja) → esperado (verde) → evidencia → impacto |
| Funcionalidad / Demo de PR | assets/feature-template.json: qué resuelve → recorrido → casos límite |
| Espera de backend o carga lenta | Ponerlo en su propia escena con "speedup": 4; solo la parte posterior a la narración se acelera |
Ventana emergente nativa <select>, diálogo del SO, o la aplicación necesita la sesión real del usuario (Trip2 con sesión iniciada) | "recorder": "gdigrab" (solo Windows). Antes de ejecutar: el usuario inicia sesión en la aplicación en ego, mantiene el monitor 1 libre y está listo para cambiar ego al espacio de tarea narate-<nombre> cuando el ejecutor lo solicite (ego mantiene ocultas las ventanas del Agent; el ejecutor las eleva con Win32 pero ego solo pinta el espacio seleccionado). Ejecución desatendida = usar playwright |
El script gdigrab usa call/actionsModule o waitForResponse | No soportado (error de validación): usar un backend real o un servidor local (examples/bug-demo/server.mjs) y waitFor en el resultado de la UI |
| La ejecución de gdigrab falla con "never became visible on screen" | La ventana del espacio de tarea estaba oculta o cubierta. Preguntar al usuario que seleccione el espacio en ego y volver a ejecutar; no reclamar ni reutilizar el espacio o pestañas del usuario |
| Necesidad de simulación (mocking) o pasos complejos | actionsModule con funciones exportadas async (page, ctx), llamadas con { "call": "nombre" } |
| Paso de evidencia de un bug | Leer out/<nombre>/evidence.json (respuestas fallidas, errores de consola) de una primera ejecución y colocar la solicitud/estado real en la llamada evidencia |
Pasos de Ejecución
- Copiar la plantilla correspondiente junto al trabajo (Trip2:
pr-assets/<nombre>.json) y completartitle,baseUrl, escenas, selectores. node bin/narrate.mjs validate <archivo>; corregir cada ruta reportada.- Si la aplicación necesita una sesión: con
playwright, pedir al usuario que ejecutenode bin/narrate.mjs login <url> --save pr-assets/state.json, luego establecerbrowser.storageState. Congdigrab, el usuario inicia sesión en la aplicación en ego de antemano (ruta Trip2:baseUrl= la URL local de Trip2,recorder: "gdigrab", escenas cortas, sincall). node bin/narrate.mjs run <archivo>(otts,record,assemblepor separado;assemblesolo vuelve a renderizar sin grabar de nuevo).- Verificar el resultado: extraer fotogramas al inicio de las escenas (
scenes.json) conffmpeg -ss <t> -frames:v 1y revisarlos; confirmar el audio convolumedetect; leerevidence.json(vacío con gdigrab). Con gdigrab, confirmar que los fotogramas muestren solo la página (sin escritorio, barra de tareas u otra ventana encima). - Entregar
<nombre>.mp4(H.264 + AAC + subtítulos suaves) y<nombre>.srt. Para PRs de Trip2 seguirtrip2-pr-delivery: artefactos enpr-assets/, adjuntos al PR, listados en la descripción.
Referencia de Acciones
goto (relativo a baseUrl), click, hover, check (selector), fill/select {selector, value}, press {key, selector?}, scroll {selector? | y?}, wait (ms), waitFor (selector o {selector, state, timeoutMs}), waitForResponse (subcadena de URL, también acepta una respuesta ya vista en la escena), overlay {kind: actual|expected|info, title?, text | html, durationMs?}, screenshot (nombre), call (exportación de actionsModule). Los selectores son localizadores de Playwright (#id, text=Guardar, role=button[name="Guardar"]). Con recorder: "gdigrab" los selectores se pasan a ego tal cual: CSS plano, text=..., loc=role:button[name='Guardar'], @ref; call y waitForResponse se rechazan; check, scroll {selector} y waitFor usan page.evaluate/waitForFunction para selectores CSS planos.
Campos de escena: id (slug), say, chapter {title, description?, durationMs?}, actions, speedup. Nivel superior: title, baseUrl, recorder (playwright | gdigrab), gdigrab {framerate: 25, drawMouse: true, tab: "new"}, viewport (solo Playwright), tts {engine: edge|deepgram|sapi, voice, rate, fallback}, browser {channel, headless, locale, storageState}, captions, showActions, gapMs, actionsModule, output.
Contrato de Salida
Devolver: ruta y duración del video, ruta del SRT, motor TTS utilizado (y cualquier fallback), escenas con sus tiempos de inicio, lo que capturó evidence.json, y cualquier cosa que no se haya podido mostrar (ventanas emergentes nativas, pasos inestables).
Referencias
assets/bug-template.json,assets/feature-template.json— esqueletos de guion.README.mddel repositorio — instalación, comandos, cómo funciona la sincronización.examples/bug-demo/— ejemplo completo funcional con un backend simulado (narration.json, Playwright) y la variante gdigrab (narration-ego.json+server.mjs).