AGENTIC QA · WORKFLOW SKILL · SHIFT-LEFT
QA pre-sprint sobre un lote de Stories del backlog: refina los Acceptance Criteria, saca a la luz gaps y ambigüedades, y deja redactado el ATP real de cada Story en madurez outline. Los defectos se previenen en los requisitos, antes de que alguien escriba una línea de la feature.
el mapa completo: índice mental del deck
GATE espera aprobación humana · caja punteada fallback / camino adyacente · → handoff a otra skill
El agente reescribe los ACs como Given/When/Then con datos concretos, saca a la luz gaps y ambigüedades, redacta el ATP pre-sprint en el campo de la Story y aplica el Test-Design Checklist. La persona firma el lote de Stories candidatas y el resumen por Story, y nunca deja pasar una Story a Estimation sin eso. Evidencia que sobrevive: los ACs reescritos, los gaps como preguntas abiertas a PO/Dev, la label fechada y la subtask de revisión. Autonomía CSA 2 y sin verificador separado: el PO o el dev que refina la Story es el revisor natural.
antes de la Phase 0: readiness gate
Lo que el usuario ya dijo (los IDs de Story, la modalidad, "groom the backlog") cuenta como respuesta dada. Solo se preguntan los gaps reales, todos juntos, en UN checklist.
Cada capacidad se verifica con un probe real. Un RED bloqueante detiene la sesión: la skill nombra la env var exacta, apunta a .env y pide reiniciar la sesión del agente.
| Capacidad | Necesidad | Probe / por qué |
|---|---|---|
| /acli (issue tracker) | REQUIRED | bun run jira:check: todo el output del refinamiento aterriza en Jira |
| Modalidad TMS resuelta | REQUIRED | A: Xray · B: Jira-native. Se persiste para /sprint-testing; el ATP pre-sprint vive en el campo en AMBAS |
/xray-cli + creds XRAY_* | N/A | No se usa pre-sprint: el ATP es field-first y el Test Plan item lo crea /sprint-testing Planning desde el campo |
| Mapas de negocio + MTP | REQUIRED | business-data-context, business-api-context y business-e2e-context existen Y están generados: bun run context:map <slug> --list lista secciones, sin aviso de placeholder. Más master-test-plan.md. Falta la skill → bun sync · placeholder → el modo de project-context · falta el MTP → bun run context:hydrate (y si el Epic no tiene plan, modo test-plan) |
| Lista de candidatos | REQUIRED | IDs explícitos o JQL de backlog, tamaño confirmado con el usuario |
Shift-left nunca ejecuta contra un sistema vivo: env de la app, credenciales de test-user, DBHub, OpenAPI, Playwright y resend son N/A aquí. La viabilidad se establece LEYENDO código, APIs y schema, jamás corriendo la app.
phase 0: session resume check + init
progress.md del batch? → ofrecer resume / restart / abort. Restart archiva lo anterior como -aborted.test-documentation §Phase 0 (A: Xray · B: Jira-native); solo pregunta si fallan los chequeos. Se persiste en plan.md §Inputs./acli siempre (escrituras + búsqueda trivial). Lecturas de detalle → bun run jira:sync-issues, nunca acli view.bun run context:map <slug> --list por cada mapa de negocio + el master test plan. Que el archivo exista no alcanza: un placeholder pasa ese chequeo vacío. Aviso de placeholder o plan ausente → STOP → /project-discovery o el modo de project-context.plan.md (Goal · Inputs · fases · riesgos) + primer entry en progress.md..session/shift-left-testing/2026-07-06-payments/ ├─ plan.md # canónico: modalidad + candidatos + fases ├─ progress.md # append-only, 1 entry por fase → resume ├─ candidates.md # output de Phase 1 └─ batch-report.md # output de Phase 3 # buffer [LOCAL] por Story (gitignored, desechable # una vez que Phase 3 lo publica en el campo ATP): .context/PBI/epics/EPIC-<KEY>-<slug>/stories/ STORY-<KEY>-<slug>/shift-left-refinement.md # al cerrar: mv → .session/.archive/<fecha>-...-<batch-id>/
phase 1: selection · el embudo de triage
$ bun run jira:sync-issues get UPEX-100 --include-comments # 1 Story: ACs + custom fields + comments $ bun run jira:sync-issues jql "project = UPEX AND issueType = Story AND status in (Backlog, ...)" # NUNCA `acli view` para custom fields: devuelve null. `acli search` solo para la lista trivial.
Solo Stories. Bug / Spike / Sub-task / Tech-debt → rechazo CON motivo de una línea, nunca en silencio.
Ya shift-left-reviewed y una label fechada de <30 días? Se muestra aparte: el usuario decide skip o refresh.
Money / auth / data-integrity / integración / state machine → FORZAR FULL. CSS puro / copy / docs → SKIP.
Solo sin veto. Feature nueva +3 · datos dinámicos +3 · AC-light +2 · esfuerzo +2 · >5 comentarios +1…
Lectura de los mapas de datos y API (bun run context:map) y del master-test-plan, sin queries ni API calls. Si el modelo de datos no soporta los ACs → flag DATA-FEASIBILITY-RISK (suave: no bloquea, se vuelve pregunta crítica al PO).
phase 1: el veto vence al score · gate de candidatos
| Score | Nivel | Profundidad de refinamiento |
|---|---|---|
| 0-3 | LOW | SKIP: PO/Dev escriben los ACs sin QA |
| 4-7 | MEDIUM | Refinamiento estándar (Fases 1-3 + outlines) |
| 8+ | HIGH | Extendido: más caza de ambigüedades y edge cases; set de preguntas ampliado |
El usuario puede rescatar una LOW si huele complejidad oculta. Y el VETO cortocircuita: una Story de refunds es refinamiento obligatorio aunque puntúe 2; un retoque de CSS es skip aunque toque cinco archivos.
Phase 1 termina con una tabla ranqueada: Accepted (riesgo · score · veto override · data-feasibility), Rejected (no-Story, con motivo), Skipped (LOW), Already Reviewed (skip/refresh?), orden recomendado y preguntas abiertas.
No se refina nada hasta que el humano confirme el set. Puede vetar Stories, rescatar LOWs o cambiar el orden. La lista aceptada final se persiste en progress.md, dentro del entry de Phase 1.
Tras el OK, por cada Story aceptada: find-or-create de la subtask [QA] Shift-Left Review con assignee = self desde el create. Nace en {{jira.status.subtask.active}} (status ACTIVE) y ahí queda hasta Phase 3; si ya existía cerrada, se reabre con reactive. Sin work type subtask en el catálogo → skip con warning, nunca bloquea.
phase 2: refinement · un subagente por story, secuencial
Reuso deliberado: la mayor parte de la lógica vive en sprint-testing/references/acceptance-test-planning.md §Fases 1-3; el subagente la cita y aplica el delta shift-left. Secuencial por diseño: presentas cada resumen al usuario antes de despachar la siguiente Story.
/sprint-testing)/sprint-testing o Documentation (/test-documentation), según la modalidadevidence/: no hay nada que capturarphase 2: story quality analysis + doctrina de diseño
Toolkit: refinement-questions.md, catálogo por arquetipo (auth, money, search, state machine, integración, RBAC).
NEEDS PO/DEV CONFIRMATION, textual, hasta Jiraphase 2: el buffer de staging + gate por story
├─ Phase 1 · Critical Analysis ├─ Phase 2 · Story Quality Analysis ← el corazón ├─ Phase 3 · Refined ACs │ Given user with active OTP <5 min │ When submits code "000000" (wrong) │ Then UI "Invalid code" · API 401 · DB no session │ NEEDS PO/DEV CONFIRMATION ← si fue inferido ├─ Phase 4 · Test Outlines (pre-sprint) ← nombres + coverage ├─ Phase 5 · Edge Cases (pre-sprint) ← nombres + criticidad ├─ Story Quality Assessment · Critical Questions for PO ├─ Technical Questions for Dev · Suggested Improvements └─ Data feasibility flags · Recommended testing strategy
.context/PBI/** (gitignored): existe solo en la máquina que corrió el lote. Phase 3 publica su body completo en el campo ATP y desde ahí la copia canónica es la de Jira./sprint-testing cortocircuita leyendo el acceptance-test-plan.md SINCRONIZADO, nunca este archivo. Los espejos Jira (story.md, acceptance-criteria.md) solo los genera el sync.context.md mínimo. Sin evidence/.Should <behavior> <condition>, agrupados por tipo con tabla de coverage (Positive / Negative / Boundary / Integration).Phase 2.<n> en progress.md y recién entonces despacha la siguiente Story.phase 3: handoff · 6 mutaciones jira por story (vía /acli)
Refined ACs al campo acceptance_criteria. Fallback si no existe: comentario "## Acceptance Criteria". Verifica con re-sync.
Append de "QA Refinements (Shift-Left Analysis)": edge cases + reglas aclaradas + preguntas. Leer primero, NUNCA sobrescribir.
Puebla el campo acceptance_test_plan con el ATP pre-sprint (madurez outline), field-first: el Test Plan item "ATP: {STORY-KEY}: {título}" NO se crea aquí; lo crea /sprint-testing Planning desde este MISMO campo, sin variante de título. Fallback si el campo no existe: comentario "## Acceptance Test Plan (ATP)".
UN comentario de handoff: puntero al campo (@PO / @Dev-lead solo si están en project.yaml). Body completo inline SOLO si el campo no existe.
shift-left-reviewed + shift-left-{YYYY-MM-DD}. qa_assignee = self, read-before-write, vía REST PUT (acli no escribe customfields).
analyze → estimate y STOP en Estimation. La subtask [QA] Shift-Left Review recibe las anotaciones exhaustivas de sesión y se cierra con complete → Close (la Story queda limpia). Re-sync: el ATP aterrizó en el campo y el comentario es un PUNTERO; el body inline solo aplica en modo fallback. test-documentation modo repair-traceability lo audita después.
Los cuerpos rich-text (ATP, ATR, descripción del Test) se escriben en Markdown, se convierten y validan con el conversor .agents/skills/acli/scripts/md-to-adf.ts, y lo que se publica es el ADF JSON resultante; por la vía CLI, acli nunca convierte Markdown solo. Markdown crudo se ve en Jira con # y ** literales; ADF artesanal se aleja del contenido que audita repair-traceability.
phase 3: guardrails de transición + resume
| Status actual | Acción |
|---|---|
| Backlog | analyze → Shift-Left QA, luego estimate → Estimation |
| Shift-Left QA | solo estimate |
| Estimation | nada: ya está en el objetivo |
| Más allá (Ready For Dev…) | SKIP + warning: el refinamiento aterriza igual, el workflow no se toca |
QA jamás avanza estimate → ready_for_dev ni compromete la Story a un sprint. Y NUNCA se transiciona a Estimation sin el ATP pre-sprint poblado: ese ATP es lo que hace estimable a la Story (anti-patrón L5).
Close no se re-transiciona y las anotaciones van como comentario nuevo (sin subtasks en el proyecto → skip con warning)phase 3: cierre de cada story · light stage verifier + definition of done
[ ] Story en {{jira.status.story.estimation}} vía analyze → estimate, y STOP ahí (ya más allá: refinamiento sí, transición no) [ ] Subtask [QA] Shift-Left Review en Close vía complete (N/A declarado si no hay work type subtask) [ ] Assignee de la subtask = self, desde el create [ ] Todo slug sin mapear pasó por el fallback §4 (se preguntó; nunca un skip en silencio) # + las líneas comunes del template: # artifact-lifecycle.md §5
Cada línea es YES o un N/A declarado con su motivo; una línea en blanco cuenta como fallo. Un NO deja el stage en NEEDS REVISION: se arregla o se reporta, nunca se avanza. "Ligero" quiere decir lo que el agente ya hizo, más a lo sumo UNA lectura de la Story.
stage-gates.md)El orquestador la verifica contra el reporte del subagente y lo que hay en Jira ANTES de escribir el checkpoint status: completed:
trivially atomicNEEDS PO/DEV CONFIRMATIONSi el proyecto renombró los status y falta un slug (por ejemplo el complete de la subtask), la skill lista las transiciones VIVAS de la issue, hace UNA pregunta con la mejor candidata, dispara el id vivo con tu OK y recomienda bun run jira:sync-workflows. .agents/jira-workflows.json es generado: nunca se edita a mano.
phase 3: cierre de sesión · batch report + archive
DATA-FEASIBILITY con pre-work requerido.session/shift-left-testing/<batch-id>/batch-report.mdprogress.md → Archive: la carpeta de sesión se mueve a .session/.archive/mem_session_summary con el resumen + ruta del archivecierre de sesión: session footer + mejoras propuestas
### Session Footer: Tools & Testing Levels Skills loaded: shift-left-testing, acli MCPs used: none CLIs used: acli, bun (jira:sync-issues, context:map) Testing levels touched: - UI/E2E: none (pre-sprint, la feature no existe) - API/Integration: none - Database: none - Unit: none Refinements proposed: 1 → .session/shift-left-testing/<batch-id>/refinements.md
evidence/.refinements.md y nunca se aplican a la skill en vivo (skill-refinement-protocol.md).Un paso equivocado, un verificador faltante o una regla vieja se reporta upstream según agentic-qa-core/references/upstream-feedback.md: borrador redactado en local, se publica solo con tu OK explícito y se verifica con gh issue view.
opcional · lotes grandes · fleet seam
El refinamiento es secuencial por defecto y así se queda. El fleet (una sesión de worker persistente por Story y un conductor que junta sus reportes) entra solo cuando el usuario lo pide explícitamente para un lote grande.
La skill solo escribe en Jira: sin código, sin branch, sin índice git en disputa. Un worktree por Story sería puro costo.
launch.txt, siempreEl conductor escribe .session/shift-left-testing/<batch-id>/launch.txt, una línea autocontenida por Story, haya o no transporte de orquestación en la máquina. Lanzar, supervisar y cerrar esas sesiones es de orca-orchestration; si nada puede lanzarlas, una persona pega esas líneas.
El conductor presenta el resumen de cada worker a medida que llega y espera el mismo approve / veto antes del handoff de Phase 3 de esa Story. Un fleet que se saltea esto ya no está corriendo esta skill.
Dos workers nunca refinan la misma Story, y toda escritura Jira de una Story es de su worker. El batch report y el comentario en el epic quedan en el conductor.
Cuando la máquina no tiene transporte de orquestación, la skill no lo menciona: no aparece en el preflight, ni en el batch report, ni en el chat. El launch.txt queda escrito igual.
cómo invocar · qué sigue en el pipeline
# Claude Code: slash + la lista de Stories como args > /shift-left-testing UPEX-100,101,102 # OpenCode y Codex: la skill se nombra en prosa > cargá la skill shift-left-testing para UPEX-100,101,102 # sin IDs, arma la JQL de backlog: > groom the backlog
Sin modos: la skill no tiene ## Mode routing ni modo single-issue. Los args son la lista de Stories; para una urgente, una lista de largo 1.
| Después necesitas… | Skill |
|---|---|
| La Story llega a Ready For QA | /sprint-testing: lee los labels (<30 días) y el ATP publicado en el campo, y solo con los dos cortocircuita sus fases de planning |
| TCs formales + ROI, cuando la Story shippea | /test-documentation (Documentation) |
| Código de test automatizado | /test-automation (Automation) · luego /regression-testing (Regression) |
| Falta contexto de negocio | /project-discovery + /project-context (modos data / e2e / api y test-plan) |
| Revisión adversarial del refinamiento (opcional) | /judgment-day, nunca auto-invocado |
← → navegar · O overview · S presentador · N notas · F pantalla completa