AGENTIC QA · WORKFLOW SKILL
Ejecuta la suite en CI, clasifica cada fallo con evidencia y convierte el resultado en un veredicto de release defendible: GO / CAUTION / NO-GO.
→ avanzar · O overview · S presentador · N notas · F pantalla completa
mapa completo — este es el índice del deck
antes de todo · preflight gate (obligatorio)
| Capacidad | Nivel | Por qué aquí |
|---|---|---|
| gh CLI autenticado | REQUIRED | Todo el pipeline vive en gh: trigger, watch, download. Sin auth → STOP, el usuario corre gh auth login. |
| Workflow files | REQUIRED | .github/workflows/ debe tener el YAML de la suite elegida con sus inputs. |
| GitHub Actions Secrets | REQUIRED | El runner usa secrets.<ENV>_USER_EMAIL/_PASSWORD + XRAY_*/ATLASSIAN_*. Verificar con gh secret list — el gap silencioso más común. |
| Allure local | REQUIRED | bunx allure resuelve (devDep, versión en package.json, sin install global) + allurerc.mjs presente para bun allure:agent. |
| Env activo confirmado | REQUIRED | Confirmar el target antes de un run largo (default: staging). |
| [TMS_TOOL] · [ISSUE_TRACKER_TOOL] | OPTIONAL | TMS solo si testing.tms_cli está en .agents/project.yaml: entonces la Fase 1 crea el RTR antes del trigger (/xray-cli en jira-xray). /acli solo si el veredicto obliga a abrir issues. |
args-as-answers — suite, env y grep/test_file ya vienen como argumentos: pregunta solo los huecos. probe, don't assume — cada capacidad se prueba con un comando real. Gaps + REDs se presentan en UNA checklist; cualquier RED bloqueante → STOP.
phase 0 · session resume check (obligatorio, inline)
Scope = <env>-<YYYY-MM-DD> (ej. staging-2026-07-06). Estado en .session/regression-testing/<scope>/{plan.md, progress.md}. Si progress.md no existe → sesión nueva. Si existe → ofrecer resume / restart / abort (restart archiva primero).
Si el Monitor murió a mitad del watch pero plan.md ya capturó el RUN_ID, la skill se re-engancha al run vivo en lugar de re-disparar el CI: se ahorra la corrida entera. El RTR_KEY también vive en plan.md, así la sesión retomada sabe en qué Execution importó CI.
# progress.md dice "Phase 1.Trigger completed" pero el Monitor no reportó: $ gh run view <RUN_ID> --json status,conclusion { "status": "in_progress" } → re-atacharse al watch, NO re-disparar
fase 1 · execute — elegir la suite
| Suite | Workflow | Duración | Usar cuando |
|---|---|---|---|
| regression | regression.yml | larga (lee la del último gh run view) | Validación pre-release, corrida nocturna completa. Única suite con RTR. |
| smoke | smoke.yml | corta | Health check post-deploy, solo tests @critical |
| sanity | sanity.yml | variable | Una feature / un archivo / un patrón grep |
"run regression" pelado → regression en el env por defecto · "smoke" o "critical only" → smoke · un archivo o grep → sanity.
En sanity, grep y test_file son mutuamente excluyentes — pasar ambos hace que el workflow ignore uno en silencio. Elige uno.
fase 1 · execute: el registro de la corrida nace antes que la corrida
El RTR (Regression Test Results) es una Test Execution RTR: {scope-id}: Regression Testing, con scope-id <env>-<YYYY-MM-DD> o un tag de release. CI importa en su key, nunca en un secret compartido. Solo la suite regression tiene RTR.
Buscar el Test Plan RTP: {PROJECT_KEY}: Regression Test Plan. Si falta, no se crea aquí (es la promoción de /test-documentation): el RTR nace sin testPlan, el hueco queda como N/A declarado en el verificador y en el reporte, y se recomienda correr la promoción.
Parent QA Test Artifacts, Test Environment = env activo, assignee = uno mismo, testPlan → RTP. Un RTR del mismo scope todavía activo (re-run por ENVIRONMENT, sesión retomada) se reutiliza. Si ya está cerrado con veredicto, la corrida nueva es un RTR nuevo con #2 en el scope-id.
RTR_KEY va a plan.md §Inputs, en la línea donde después cae el RUN_ID, y sale hacia CI como -f execution_key=$RTR_KEY. Ese input pisa el secret STP_EXECUTION_KEY, que queda solo para corridas programadas sin key.
Cierre de sprint: el objetivo es el STR STR: Sprint#{N}: Regression Testing (testPlan → STP y → RTP), con N dado por el usuario o por el STP, nunca inventado. jira-native: no hay RTR; el trigger va sin execution_key.
Un RTR cerrado no vuelve atrás (la transición reactive no se usa). Una corrida posterior al veredicto, por ejemplo el re-run de un NO-GO ya corregido, abre su propio RTR.
fase 1 · execute: plan, RTR, trigger, RUN_ID
# 1 · preflight de fase (siempre) $ gh auth status && gh repo view --json name,owner && gh workflow list # 2 · escribir .session/regression-testing/<scope>/plan.md ANTES del trigger # 3 · crear el RTR (slide anterior) → RTR_KEY en plan.md §Inputs # 4 · disparar la suite con inputs explícitos $ gh workflow run regression.yml -f environment=staging -f execution_key=$RTR_KEY \ -f video_record=false -f generate_allure=true # smoke y sanity: sin RTR y sin execution_key (nunca escriben en una Execution de regresión) $ gh workflow run smoke.yml -f environment=staging -f generate_allure=true $ gh workflow run sanity.yml -f environment=staging -f test_type=e2e -f grep="@auth" # grep O test_file, nunca ambos # 5 · capturar RUN_ID (esperar unos segundos: el run no es consultable al instante) $ RUN_ID=$(gh run list --workflow=regression.yml --limit=1 --json databaseId -q '.[0].databaseId')
El RUN_ID se añade a plan.md §Inputs, junto al RTR_KEY, y progress.md registra ambos. Sin RUN_ID persistido no hay re-attach; sin RTR_KEY una sesión retomada no sabe en qué Execution importó CI. En jira-native se omite execution_key en todas las suites.
Registra el commit probado en el reporte (gh run view <RUN_ID> --json headSha) y compara tendencias solo entre runs con commit conocido: commit distinto, baseline distinta. Y video_record=true infla mucho los artefactos: solo para depurar.
fase 1 · execute — monitor (dispatch background)
$ gh run watch <RUN_ID> --exit-status # fallback si watch expira en suites largas: poll cada 60–90s $ gh run view <RUN_ID> --json status,conclusion status: queued | in_progress | completed conclusion: success | failure | cancelled | timed_out (solo al completar)
fase 2 · analyze — collect (dispatch parallel ×3)
# inline (hilo principal): contexto + SOLO logs fallidos (--log completo vuelca cada step) $ gh run view <RUN_ID> --log-failed $ gh run view <RUN_ID> --json artifacts --jq '.artifacts[].name' # subagentes en paralelo: uno por artefacto que lista el comando anterior $ gh run download <RUN_ID> -n merged-allure-results-staging -D ./analysis/ # A $ gh run download <RUN_ID> -n e2e-failure-evidence -D ./analysis/evidence/ # B $ gh run download <RUN_ID> -n e2e-playwright-report -D ./analysis/playwright/ # C # run anterior → baseline de tendencia $ PREV=$(gh run list --workflow=regression.yml --limit=2 --json databaseId -q '.[1].databaseId') $ gh run download $PREV -n merged-allure-results-staging -D ./analysis/previous/
Nunca saltes la descarga de Allure en builds rojos — screenshots, traces y videos desaparecen al vencer la ventana de retención. Evidencia primero, análisis después.
fase 2 · analyze — parse + métricas
| Métrica | Fórmula |
|---|---|
| Pass Rate | Passed / Total × 100 |
| Pass Rate (gating) | sobre Total − KNOWN-BLOCKED |
| Duración | max(stop) − min(start) |
| Trend | pass rate actual − run previo |
Los conteos (total, passed, failed, skipped) salen de reports/test-outcomes.json: Allure archiva una falla esperada como passed y puede leerse verde sobre tests que nunca se observaron pasar. Allure manda para el detalle de cada falla (statusDetails, labels[]: testId = ATC ID, suite, severity) y para el historial que exige FLAKY; solo si el archivo no está en los artefactos descargados, los conteos salen de Allure y el reporte lo dice. Detalle: Allure > Playwright report.json > logs crudos.
@smoke/@regression/@e2e/@integration/@critical es la única taxonomía: el suite que lees ES el scope que CI corrió. Nunca reconcilies contra otro set de labels.
La política anti-retry es retries: 0 (ver playwright.config.ts) — doctrina anti-retry: un reintento solo enmascararía el flake. La flakiness aparece como fallo intermitente normal y la clasifica la regla de historial (>20% en los últimos 10 runs), nunca un pass-on-retry. Si un proyecto downstream habilitó retries conscientemente, aplica el anti-patrón R3: expón el conteo de retries en el reporte, no solo el status final.
fase 2 · analyze — clasificar cada fallo (6 vías)
Test fallido ├─ tag @blocked:{BUG-KEY}? ──────────────► KNOWN-BLOCKED (aparcado; fuera del gating) ├─ un ticket conocido ya lo rastrea? ────► KNOWN ISSUE ├─ patrón de error de entorno? ──────────► ENVIRONMENT │ ECONNREFUSED · ETIMEDOUT · net::ERR_ · Navigation timeout · browserType.launch · 502/503 ├─ sin historial (primer run)? ──────────► NEW TEST ├─ ≥5 runs y falla >20% (mismo build)? ─► FLAKY ├─ 1-4 runs de historial? ───────────────► REGRESSION (etiqueta INSUFFICIENT HISTORY) └─ cualquier otro caso ──────────────────► REGRESSION ← bloquea el release
NUNCA marques REGRESSION sin revisar el historial primero. Y un primer fallo sin historia no es regresión: es NEW TEST — se verifica a mano una vez antes de clasificar.
>10 fallos → chunks de ~10 con un subagente clasificador por chunk (cap 10), merge de JSONs en el hilo principal. ≤10 → inline: el overhead no se justifica.
Toda clase salvo REGRESSION deja pasar el fallo, y quien la elige es el clasificador. Por eso cada una se sostiene solo con su cita (tabla de la slide siguiente). Sin cita, cita vacía o un ticket que esta misma sesión creó para volver «conocido» el fallo: cuenta como REGRESSION.
fase 2 · analyze — de la etiqueta a la acción
| Categoría | Impacto | Acción | Issue en Jira? | Evidencia que debe citar |
|---|---|---|---|---|
| KNOWN-BLOCKED | LOW | Excluir del gating, listar con su {BUG-KEY} | No — el marker ya nombra el bug abierto | El tag @blocked:{BUG-KEY} del spec y su bug key |
| REGRESSION | HIGH | Bloquea el release, archivar y asignar | Sí — Bug/Defect (Fase 3) | Ninguna: es el valor por defecto |
| FLAKY | MEDIUM | Agendar estabilización, no bloquea | No | Ids y resultados de al menos 5 runs sobre el mismo build |
| KNOWN ISSUE | LOW | Documentar contra el ticket existente | No | La key de un ticket creado antes del run que nombre el test |
| ENVIRONMENT | MEDIUM | Re-run tras revisar la infra | No | La línea de log que coincide con el patrón, más los otros tests caídos en el mismo host |
| NEW TEST | LOW | Verificación manual primero | Solo si se confirma defecto real | La consulta de historial (Allure, runs del TMS) que volvió vacía |
ECONNREFUSED a tu propia API suele significar que la app se cayó. Muchos tests sin relación rojos en el mismo host → ENVIRONMENT; UN test fallando en un endpoint que otros usan bien → probable REGRESSION disfrazada.
Solo en suites integration-trunk: un rojo clase ENVIRONMENT en Sanity-CI puede autorizar merge al trunk de integración (nunca al PR final a main) si el cambio pasó en local + staging y el rojo existe sin el cambio. REGRESSION jamás califica.
fase 2 · analyze — severidad por fallo
Un test FLAKY sobre el checkout sigue siendo CRITICAL. La clasificación responde por qué falló; la severidad, cuánto nos importa.
| Severidad | Criterio |
|---|---|
| CRITICAL | Flujo central del usuario (login, checkout, payment) — o cualquier test con tag @critical |
| HIGH | Feature mayor (search, profile, dashboard) |
| MEDIUM | Feature secundaria (filtros, preferencias) |
| LOW | Edge case o ruta solo-admin |
Bloque de análisis: tabla de métricas + delta de tendencia, una sección por categoría (Regressions primero), detalle por test fallido (nombre, ATC ID, suite, error, last-pass, screenshot) y un veredicto preliminar.
después de la fase 2 · fleet seam (opcional)
El triage nunca se reparte entre sesiones: una sola sesión conductora lee el run, clasifica y es dueña del veredicto. La flota sirve para lo que viene después, cuando la clasificación deja varios clusters independientes que necesitan código, y solo si el usuario pide trabajarlos a la vez.
Un cluster = un worker = un worktree = una rama. Nunca dos workers sobre el mismo cluster: dos sesiones en un mismo checkout se pisan el índice de git aunque toquen archivos distintos. Cada fix se escribe bajo /test-automation (Plan → Code → Review) y aterriza según git_strategy.
La conductora escribe .session/regression-testing/<scope>/launch.txt, una línea autocontenida por cluster, exista o no un orquestador en la máquina. Lanzar y supervisar es cosa de /orca-orchestration; si nada puede lanzarlas, esas líneas se pegan a mano en terminales.
GO / CAUTION / NO-GO, las métricas, el RTR (o el STR de cierre de sprint) y toda escritura en Jira quedan con la conductora. Un worker arregla su cluster y reporta: no re-puntúa el run, no archiva el defecto, no transiciona el RTR.
Si no hay transporte de orquestación, la skill no lo menciona: ni en el preflight, ni en el bloque de entorno, ni en el reporte. El launch.txt es el fallback y ya está escrito.
fase 3 · report & decide — el score de 10 puntos
| Factor | +3 | +1 | 0 | −1 | −2 | −3 |
|---|---|---|---|---|---|---|
| Pass Rate | ≥95% | 90–95% | — | — | <90% | — |
| Regressions | 0 | 1–2 Low | — | 1+ Medium | — | High/Critical |
| Tests @critical | Todos pasan | — | — | — | — | Cualquier fallo |
| Flaky | — | ≤3 | 4–5 | >5 | — | — |
Release aprobado; smoke post-deploy agendado.
Revisión manual; riesgos aceptados documentados.
Release bloqueado; fix + re-run planificados.
(1) falla cualquier test @critical · (2) existe cualquier REGRESSION HIGH/CRITICAL · (3) pass rate < 90%. Anulan cualquier score. R2: el gate es binario — REGRESSION conocida > 0 = no hay GO. R6: nunca mezclar smoke + regression en un solo pass-rate.
fase 3 · report & decide — archivar defectos (NO-GO / CAUTION con regressions)
Solo REGRESSION y NEW TEST confirmado llegan a Jira. Tipo según el ciclo de vida de la FEATURE, no dónde falló: ya live sobre Staging → Bug · pre-release → Defect · comportamiento deseable más allá del AC → Improvement.
severity → priority auto-derivada · components = módulo afectado · root_cause + error_type + test_environment · qa_assignee = uno mismo (read-before-write) · evidence = link Allure + ./analysis/evidence/.
Parent = epic QA Defect Management (nunca un epic de producto) · issue-link causal → la Story que cubre el ATC regresionado · components = módulo de producto.
Cargar /acli primero (auth + sintaxis). Crear con acli workitem create --from-json; customfields sobre issue existente vía REST PUT /rest/api/3/issue/{KEY}. Filing gate de la doctrina antes de enviar; guardar la key para el reporte.
agentic-qa-core/references/defect-management-doctrine.md — la misma autoridad que usa /sprint-testing. FLAKY, ENVIRONMENT y KNOWN ISSUE nunca generan bug nuevo.
fase 3 · report & decide: veredicto en el RTR, reporte local, archive
# el RTR existe desde la Fase 1 y CI ya importó en él [TMS_TOOL] Update Test Execution <<RTR_KEY>> results: solo lo que el import de CI no dejó [ISSUE_TRACKER_TOOL] Add Comment <<RTR_KEY>> body: GO / CAUTION / NO-GO, score, blockers, links [ISSUE_TRACKER_TOOL] Transition complete # active → close # RTP: queda en ready, nunca se completa
## Executive Summary Verdict + score/10 + 1 línea ## Release Blockers si NO-GO: regressions + owner + ETA ## Failure Details Regressions → Flaky → Known → Blocked → Env ## Trend · ## Links (RTR key) · ## Recommendations
Es el RTR en el TMS (el STR solo en la corrida de cierre de sprint) más el comentario GO / CAUTION / NO-GO publicado en él. El RTR se cierra vía complete después del comentario, nunca antes y nunca queda abierto. En jira-native no hay RTR: los resultados son escrituras de status por Test, el veredicto va al reporte local y a un comentario en el issue de Release si existe, con el skip declarado.
.context/reports/ está en .gitignore: es salida [LOCAL] generada y solo existe donde corrió la suite. Nada downstream puede depender de ese archivo; sirve para leer el run en frío, no como entregable.
GO → candidato aprobado + smoke post-deploy · CAUTION → revisión con el lead, riesgos por escrito · NO-GO → bloquear, asignar issues, planificar re-run (con un RTR nuevo).
Tras el veredicto: .session/regression-testing/<scope>/ → .session/.archive/ + resumen a memoria. Con NO-GO, el archive espera a que termine la creación de issues.
cierre del stage · light stage verifier + session footer
Ocho líneas comunes: artefactos por KEY, links, statuses, assignee, parent + components, campos y comentarios escritos, checkpoint en progress.md, footer impreso. Cada una es YES o un N/A declarado con su motivo; una línea en blanco es un verificador fallido y cualquier NO deja el stage en NEEDS REVISION. "Ligero" significa que se responde con lo que el stage ya hizo, más como mucho UNA lectura extra.
[ ] RTR por KEY, creado ANTES del trigger (salió como execution_key) [ ] RTR con Test Environment, assignee self, parent QA Test Artifacts [ ] RTR → RTP vía testPlan (RTP ausente = N/A declarado) [ ] Comentario de veredicto EN el RTR (no el archivo local) [ ] RTR en close vía complete, DESPUÉS del veredicto; nunca reactive [ ] Cierre de sprint: STR → STP y → RTP, cerrado tras el veredicto [ ] RTP intacto en ready [ ] jira-native: skip declarado + status por Test + reporte [LOCAL] [ ] Slug sin mapear → fallback §4 (preguntado), nunca skip mudo
Cada captura se nombra en el chat en el turno en que aparece, y al cierre va la lista completa: rutas relativas al repo, verificadas con ls, anotaciones de bugs primero. Aquí suelen ser la evidencia que se adjunta al defecto, sacada de ./analysis/evidence/.
Skills cargadas, MCPs llamados y CLIs invocados de verdad (gh, bunx allure, acli...), más los niveles de la pirámide que la suite de CI ejercitó, con "none" explícito en los que no tocó, y la línea Refinements proposed: con lo que quedó propuesto en refinements.md.
Ninguno de los dos bloques va a un comentario de Jira ni al cuerpo del RTR. Con subagentes, cada reporte de stage trae los cinco campos del footer y la conductora lo compila UNA vez al cierre.
dónde se ve el Allure de CI · github pages o portal privado
| Ruta | Qué es | Cómo se activa |
|---|---|---|
| GitHub Pages | Default. scripts/ci/publish-allure-pages.ts publica en gh-pages; la URL /{env}/{suite}/ abre el último run. | Habilitar Pages una vez: references/github-pages-setup.md. |
| Test Report Portal | Privado: Vercel (login) + Supabase (índice de runs) + bucket R2 privado. Login con email del trabajo, filtrado por dominio; retención en el portal. | El publish de regression.yml, smoke.yml y sanity.yml ya es dual: va al portal si existe el secret PORTAL_URL. Solo se cablean secrets. |
| GitHub Enterprise | Atajo sin infraestructura: visibilidad de Pages en Private. | Se ofrece primero, si la org lo tiene. |
references/private-hosting-setup.md: la IA corre cada paso (supabase, wrangler, vercel, gh secret set) y solo se detiene en los HUMAN CHECKPOINT: altas de cuentas, handshakes de login, OAuth opcional. Empieza detectando si el repo ya está cableado y cierra con un checklist de verificación (el viewUrl sin login devuelve 401, nunca bytes).
En cualquier setup de Allure o de Pages, primero: npm view allure version contra package.json. Mismo major atrasado → resumir novedades y ofrecer bun update. Major nuevo → nunca subir en silencio: breaking changes y aprobación explícita.
quién decide qué — y qué pasa después del GO
El agente corre la suite, clasifica cada fallo, computa pass-rate y tendencia, emite GO / CAUTION / NO-GO y escribe el RTR (el STR solo en la corrida de cierre de sprint). La persona firma el veredicto CAUTION, y nunca deja que el agente invente el número de sprint. La evidencia que sobrevive: el reporte Allure, el RTR enlazado a su RTP, y la historia de corridas que autoriza la palabra FLAKY.
Decide dentro de límites declarados y escala fuera de ellos; con un GO sin fallos la supervisión es por monitoreo, no por aprobación. Sin verificador separado: el único stage que lo exige es Automation. Regression es la excepción deliberada al techo de 3 del pipeline: un run sin fallos no necesita aprobación humana para avanzar, mientras que todo CAUTION o NO-GO lo firma una persona.
El pipeline no termina cuando la suite pasa. Observation es el octavo stage: producción, capacidad L4. No tiene skill — su unidad operativa es una rutina agéntica que vigila SLOs, error budget, RUM y señales de canary, abre items al backlog y alimenta el próximo Shift-Left. La persona firma los SLOs, la política de error budget y la decisión de frenar releases. Está declarado, no implementado: sin skill propio (el estado vive en agentic-qa-core/references/stage-gates.md), y decirlo así es parte de la honestidad del método.
cómo se invoca · claude code, opencode, codex
La skill no declara modos: lo que viaja después del nombre son args-as-answers (suite, env, grep o test_file). El preflight solo pregunta lo que falte; sin suite, "run regression" pelado corre regression en el env por defecto.
| Host | Cómo se invoca | Ejemplo |
|---|---|---|
| Claude Code | Slash command con la skill, args detrás | /regression-testing smoke staging |
| OpenCode | Sin slash commands: se nombra en prosa | "carga la skill regression-testing, suite smoke en staging" |
| Codex | Igual que OpenCode, en prosa | "carga la skill regression-testing y corre sanity con grep @auth" |
"run regression", "smoke suite", "analyze test results", "GO/NO-GO decision", "release readiness", "quality report", "flaky tests", "pass rate".
Los reportes privados se piden con una frase: "reportes privados", "protege los reportes con login", "no publiques evidencia pública". Lo mismo GitHub Pages ("publish the reports site") y el version-currency check ("is Allure up to date?").
cierre: qué entra, qué sale, qué queda
/regression-testing en Claude Code; "carga la skill regression-testing" en OpenCode y Codex. Detalle en la slide anterior.
Entra desde /test-automation (Automation: escribe los tests y el marker @blocked) y desde /test-documentation (promueve el RTP). Sale hacia /sprint-testing (verificar el fix a mano) y de vuelta a /test-automation (estabilizar flaky, nuevos tests). Tras un GO, el ciclo no termina: entra en Observation.
Entregable: el RTR en el TMS con su comentario de veredicto (el STR solo al cierre del sprint) e issues Jira (Bug/Defect). Salida local: .context/reports/regression-<env>-<date>.md [LOCAL], ./analysis/ (artefactos CI), plan.md + progress.md (sesión).
references/failure-classification.md (catálogo de patrones de error) · references/ci-cd-integration.md (workflows, sharding, secrets, execution_key) · references/github-pages-setup.md (publicar los reportes Allure) · references/private-hosting-setup.md (portal privado). Antes de cualquier setup de Allure o Pages: el version-currency check.
Clasifica con honestidad, respeta los vetos, y el veredicto no lo discute nadie.