Agentic QA · Skill de evidencia

/bug-screenshot-annotation

Cuando una captura cruda necesitaría un párrafo para explicar el bug, esta skill la marca como lo haría una persona de QA: un óvalo sobre la zona rota, una flecha, un texto que explica y una etiqueta BUG en la esquina. Quien abre el ticket entiende el defecto de un vistazo.

100% local: nada sale de tu máquina Dentro de /sprint-testing, Stage 2 Un solo archivo de evidencia
Deck de la skill bug-screenshot-annotation. La idea central: la anotación se dibuja con HTML y CSS encima de una captura que ya existe, se renderiza en un servidor HTTP atado a 127.0.0.1 y se captura con playwright-cli. Ningún servicio externo de imágenes toca la evidencia. Pulsá → para avanzar, S para modo presentador, O para overview, F para pantalla completa.

Cuándo usarla · 2 de 13

Para bugs que se ven, no para los que se leen

Lo que tenésCon qué
Un bug visual o de posición: elementos superpuestos, algo desalineado, una fecha corrida en el eje de un gráfico, un elemento en el lugar equivocado/bug-screenshot-annotation, antes de reportar
Un hallazgo textual: un mensaje de error, un número equivocado en un camponada: la captura cruda ya se lee sola
Capturas de antes y después que se entienden sin marcasnada: van como están
Reportar el bug en sí (título, pasos, severidad, campos)/sprint-testing, Stages 2 y 3, con sus plantillas de reporte
Una foto de un objeto físico o de un documentofuera de alcance: se habla primero con el humano sobre cómo anonimizarla

Parte de una captura que ya existe

La skill superpone formas sobre una imagen que está en disco. Nunca genera ni edita una imagen a partir de una descripción en texto.

Cómo se dispara

"annotate bug screenshot", "mark up evidence", "anota este bug", "marca la captura", "resalta el bug en la imagen".

Fuentes: description y Compact Rules del SKILL.md (cuándo sí, cuándo no, input en disco), sección Scope (Not for), y sprint-testing/references/exploration-patterns.md, "Visual/positional findings: annotate before filing" (el caso textual se saltea).

Un ejemplo real · 3 de 13

La misma captura, antes y después

Captura cruda (recortada)

Captura cruda de la página pública Broken Images: tres cuadros, dos sin imagen y uno con un avatar gris

Qué está mal? Hay que mirar con atención para notar que dos cuadros están vacíos.

Evidencia anotada

La misma captura anotada: un óvalo rojo rodea las dos imágenes rotas, una flecha las señala desde un recuadro que explica el defecto y una etiqueta BUG DEMO-2 marca la esquina

Óvalo, flecha, recuadro explicativo y etiqueta BUG: el defecto se ve sin leer el ticket.

Hecho con el proceso de este deck sobre una página pública de práctica (the-internet.herokuapp.com/broken_images, de Elemental Selenium): sin datos de producto. DEMO-1 y DEMO-2 son claves de ejemplo. El texto va en inglés porque la imagen termina en el bug de Jira, y los artefactos externos se escriben en inglés.

Ejemplo generado siguiendo el SKILL.md paso a paso: captura en una sesión anónima de playwright-cli, recorte con PIL, HTML armado copiando los bloques de references/shapes.html, servido en 127.0.0.1 y capturado con el viewport igual al lienzo. Necesitó tres pasadas de ajuste (la flecha apuntaba a la imagen sana; después el recuadro tapaba el pie de la página). El idioma del recuadro sigue la Critical Rule #14 de AGENTS.md: todo artefacto que sale a Jira va en inglés.

La regla de seguridad · 4 de 13

La evidencia de QA no sale de la máquina

Primer intento: un MCP de imágenes

Un diseño anterior mandaba las capturas a servicios externos de edición generativa. El primero tenía cuota agotada en todos sus planes. Simplemente no andaba.

Segundo intento: bloqueado, tarde

El clasificador de exfiltración del propio runtime del agente lo bloqueó: las capturas traían datos reales de producto, clientes y competencia, y el destino no era confiable. La autorización explícita del usuario en el chat no levantó el bloqueo. Antes de que lo frenaran, una captura ya había quedado en un bucket público del servicio.

La lección que quedó como regla

La evidencia de QA con datos reales de producto o de clientes nunca pasa por un servicio externo de imágenes, generativo o no. Ni con permiso en el chat.

Cómo lo evita la skill

HTML y CSS renderizados por un servidor HTTP atado a 127.0.0.1, capturados por un navegador local. Nada sale de la máquina.

Si aparece un caso que no cubre

Por ejemplo, una foto de cartelería física: la skill vuelve al humano y conversan cómo anonimizar. Nunca la manda en silencio a un servicio externo.

Sección "Why 100% local: the security rationale (binding)" del SKILL.md y su primera Compact Rule. El servidor atado a loopback cumple dos funciones: es la única forma de que playwright-cli cargue la página (rechaza file://) y es lo que mantiene el enfoque a salvo de la exfiltración.

Mapa · 5 de 13

De la captura cruda a la evidencia anotada

ENTRADA · evidence/ Captura cruda {KEY}-bug-{desc}.png SCRATCHPAD DE LA SESIÓN · NUNCA EVIDENCIA PASO 1 Ubicar la zona caja de recorte PASO 2 Recortar PIL → crop.png PASO 3 Armar el HTML bloques de shapes.html PASO 4 Servir en loopback --bind 127.0.0.1 PASO 5 Capturar viewport ≥ lienzo, ruta explícita PASO 6 Revisar y ajustar no sale a la primera otra pasada PASO 7 Limpiar matar el servidor SALIDA · evidence/ DEL TICKET EL ÚNICO ARCHIVO DE EVIDENCIA {KEY}-BUG-{BUG-KEY}-annotated.png la crop y el HTML se quedan en el scratchpad PASO 8 · EN EL MISMO TURNO Informar la ruta sin que nadie la pida PASO 9 · OPCIONAL · CON TU OK Publicar en el bug de Jira como imagen inline en un comentario Lo que pasa por el scratchpad son archivos de trabajo: se pueden volver a generar desde la captura cruda. A evidence/ entra una sola cosa, el PNG final anotado.
Sección "Process (8 steps + optional embed)" del SKILL.md. Los buckets salen de agentic-qa-core/references/evidence-conventions.md §1: la crop y el HTML son bucket C (scratchpad, descartables), el PNG final es bucket B (evidencia real). La captura cruda de entrada usa el nombre de la familia 1 de §2 ({KEY}-bug-{short-desc}.png).

Pasos 1 a 3 · 6 de 13

Recortar la zona y copiar las formas

Paso 1 · Ubicar la zona

Sobre la captura cruda (o su snapshot de accesibilidad) se calcula la caja de recorte en píxeles y dónde cae cada forma respecto de ella.

Paso 2 · Recortar con Python y PIL

from PIL import Image img = Image.open("<raw-screenshot-path>") img.crop((left, top, right, bottom)) \ .save("<scratchpad>/crop.png")

Paso 3 · El HTML de anotación

La crop entra como <img> de fondo y cada anotación es un <div> con posición absoluta encima. No se diseña desde cero: se copian y ajustan los bloques comentados de references/shapes.html.

Dos cosas que no se pierden al copiar

La escala de z-index (si se cae, la etiqueta queda escondida detrás de un recuadro) y <meta charset="utf-8"> (sin ella, los acentos se capturan como basura).

Todo en el scratchpad

La crop y el HTML son intermedios: nunca se escriben en evidence/ ni se citan desde un ticket.

Pasos 1 a 3 del Process del SKILL.md, la Compact Rule de copiar bloques de shapes.html con su escala de z-index y su meta utf-8, y los gotchas "Badge hidden behind a callout box" y "Mojibake on em-dashes / accented characters".

La biblioteca de formas · 7 de 13

Cada forma tiene su capa

Bloque de shapes.htmlPara qué
circle-calloutóvalo alrededor de la zona rota, con margen para no cortar la UI
arrow-to-regionlínea con punta; se ubica en la cola y se rota
callout-boxrecuadro blanco que explica el defecto, con ancho máximo y texto que salta de línea
badge-cornerla etiqueta roja BUG con la clave, en la esquina lejos del bug
axis-tick + axis-tagpara fechas corridas en un eje: marca y valor correcto, con la etiqueta equivocada del gráfico a la vista
before-afterdos recortes lado a lado con su leyenda

La escala de z-index

30Etiqueta de esquinasiempre arriba de todo 20Recuadrosel texto que explica 10Círculos, flechas, marcaslo que señala 1Imagen basela crop
Comentarios de cada bloque en references/shapes.html (SECTIONS y Z-INDEX SCALE) y el gotcha "Badge hidden behind a callout box" del SKILL.md: sin una escala explícita decide el orden del DOM, no la intención visual. shapes.html trae tres ejemplos trabajados: combinado, eje con fecha corrida y antes/después.

Pasos 4 y 5 · 8 de 13

Servir en 127.0.0.1 y capturar

Paso 4 · Un servidor solo de loopback

python3 -m http.server <port> \ --bind 127.0.0.1 --directory <scratchpad>

Por qué no file://?

La CLI del navegador rechaza file:// antes de renderizar. El servidor en loopback es el único camino, y además es lo que mantiene todo en la máquina.

Paso 5 · Capturar con /playwright-cli

Una sesión con nombre propio, anónima: -s=<KEY>-annotate. Se ajusta el viewport a las medidas reales del HTML (igual o más grande: uno más chico corta los recuadros) y se captura con la ruta de destino explícita en evidence/.

El nombre del archivo

{KEY}-BUG-{BUG-KEY}-annotated.png: la clave del ticket que se testea y la del bug reportado. Ejemplo: UPEX-411-BUG-UPEX-512-annotated.png. Las dos claves lo mantienen trazable aunque termine en un hilo de Slack.

Dónde está evidence/

En la carpeta del ticket bajo .context/PBI/ del checkout principal: la copia de un worktree muere con el worktree.

Pasos 4 y 5 del Process del SKILL.md y el gotcha "Callout text clipped at the edge". La sesión anónima es el caso (a) de agentic-qa-core/references/browser-sessions.md, que nombra explícitamente la página de anotación. Naming y ubicación: agentic-qa-core/references/evidence-conventions.md §1 (bucket B bajo PRIMARY_ROOT) y §2 (sufijo annotated y el ejemplo UPEX-411 / UPEX-512).

Pasos 6 a 8 · 9 de 13

Mirar el PNG, apagar el servidor, decir dónde quedó

Paso 6

Revisar y ajustar

leer el PNG; al menos una pasada más

→

Paso 7

Limpiar

kill <pid> del http.server

→

Paso 8

Informar la ruta

en el mismo turno, sin que la pidan

Lo típico de la segunda pasada

Mover o agrandar un círculo, acortar o partir el texto de un recuadro, correr la etiqueta o la flecha para que no choquen. El ejemplo del slide 3 necesitó tres.

Nada queda corriendo

El servidor se mata antes de que termine la sesión, y la sesión del navegador se cierra cuando el PNG ya está en disco.

La ruta, a mano

Tu próximo paso casi siempre es adjuntarla al bug. Por eso la ruta relativa al repo aparece apenas el PNG existe y vuelve a encabezar el grupo Bug annotations en la lista de capturas del cierre.

### Screenshots (relative paths) Bug annotations: - .context/PBI/epics/EPIC-<KEY>-<slug>/stories/STORY-<KEY>-<slug>/evidence/{KEY}-BUG-{BUG-KEY}-annotated.png
Pasos 6 a 8 del Process del SKILL.md. El contrato de informar la ruta es agentic-qa-core/references/session-footer-contract.md, Part 1 (1a inmediato, 1b consolidado al cierre, las anotaciones de bugs primero). Solo se listan archivos verificados en disco (evidence-conventions.md §3).

Paso 9 · opcional · 10 de 13

La imagen, dentro del bug

El helper de la skill /acli

bun .agents/skills/acli/scripts/jira-attach-media.ts \ <BUG-KEY> \ ./evidence/<KEY>-BUG-<BUG-KEY>-annotated.png \ --caption "Annotated evidence: <summary>" \ --publish

Sube el archivo como adjunto, resuelve el id de media de Atlassian y publica un comentario con la imagen inline.

Vos confirmás primero

La skill ofrece publicar; no publica sola. Y nunca dice que adjuntó algo si el helper no terminó bien de forma verificable.

La foto principal

Publicada, encabeza la sección Evidence del bug, delante de la captura cruda. Si el bug tiene página de evidencia, va primera en su pack: encabeza la página y es la miniatura del bug en el tracker. El Evidence Handoff del Stage 3 enlaza esa página.

Si el helper no llega

Queda el camino de siempre: la ruta está en el chat y la adjuntás vos.

Paso 9 del Process del SKILL.md y su última Compact Rule. Qué hace el helper: comentario de cabecera de .agents/skills/acli/scripts/jira-attach-media.ts (upload, resolución del UUID de media, nodo mediaSingle). Página de evidencia y miniatura: evidence-artifact/references/workflow.md §4. Evidence Handoff: sprint-testing/references/reporting-templates.md §3.5.

En el pipeline · 11 de 13

Entre explorar y reportar

/sprint-testing · Stage 2

Exploración

aparece un hallazgo y se captura crudo en evidence/

→

Visual o de posición?

Anotar antes de reportar

/bug-screenshot-annotation

→

/sprint-testing · Stage 3

Reporte del bug

el PNG anotado va primero como evidencia

Se carga adentro

Corre dentro del subagente que ya está ejecutando el stage, como /playwright-cli. No lanza agentes propios ni tiene estrategia de despacho.

Sin cierre propio

El footer de cierre lo imprime la skill dueña del stage. Esta solo garantiza que su ruta aparezca, y primera.

Las herramientas que usa

/playwright-cli para capturar, Python con PIL para recortar, http.server en loopback, y /acli solo si publicás en Jira.

Fuentes: introducción del SKILL.md (skill de referencia y utilidad cargada dentro del subagente, caller típico sprint-testing Stage 2); sprint-testing/references/exploration-patterns.md, "Visual/positional findings: annotate before filing"; session-footer-contract.md (las skills de referencia y utilidad están exentas porque corren dentro de una sesión que ya cumple el contrato). Deck hermano: ../sprint-testing/how-it-works.es.html, slide "Browser y evidencia".

Salvaguardas · 12 de 13

Lo que la skill nunca hace

ReglaPor qué
Mandar una captura de QA a un servicio externo de imágenes, ni con permiso en el chatlas capturas traen datos reales; ya hubo una fuga a un bucket público
Generar o editar una imagen desde una descripción en textola evidencia sale de una captura real que está en disco
Guardar la crop o el HTML en evidence/, o citarlos en un ticketson intermedios; la evidencia es un solo PNG
Abrir el HTML por file://la CLI lo rechaza; el camino es loopback
Capturar con un viewport más chico que el lienzocorta los recuadros en el borde
Dar por buena la primera capturasiempre hay algo que mover o reescribir
Dejar el servidor corriendo después de la sesiónel paso 7 lo cierra siempre: no queda nada escuchando
Publicar en Jira sin tu confirmaciónlo que se publica en el bug lo decidís vos
Compact Rules y Known gotchas del SKILL.md; la sección de seguridad para la primera fila. El paso 7 del Process pide matar el servidor antes de que termine la sesión.

Cierre · 13 de 13

Invocación y dónde leer más

Cómo se invoca

Claude Code: /bug-screenshot-annotation más la captura y la clave del bug.
OpenCode y Codex: cargá la skill bug-screenshot-annotation y nombrá la captura y el bug.

No tiene modos. Lo normal es que la cargue /sprint-testing sola, en el Stage 2.

Qué lee

La captura cruda en evidence/ · references/shapes.html · la clave del ticket y la del bug.

Qué deja

{KEY}-BUG-{BUG-KEY}-annotated.png en evidence/, su ruta en el chat y, si confirmaste, un comentario con la imagen en el bug.

Canon

.agents/skills/bug-screenshot-annotation/SKILL.md (regla de seguridad, proceso, gotchas) y references/shapes.html (formas y escala de capas). Buckets y nombres: agentic-qa-core/references/evidence-conventions.md.

Relacionadas: /sprint-testing la carga en el Stage 2 y reporta el bug en el Stage 3 · tooling cubre /playwright-cli y /acli.

Fin del recorrido. El mapa del slide 5 lo resume: la crop y el HTML viven en el scratchpad, el servidor solo escucha en 127.0.0.1, y a evidence/ entra un único PNG anotado. La skill no tiene "## Mode routing": se invoca por nombre.
← → navegar · O resumen · S presentador · N notas · F pantalla