SKILL.md
Skill: Validar trazabilidad de un trabajo
Genera un reporte de trazabilidad que cruza los criterios de aceptación de un trabajo contra los casos de prueba y los artefactos de prueba automatizada (unit, integración, e2e) presentes en el repositorio, y emite un veredicto sobre si el trabajo queda cubierto.
El trazado primario es para historias de usuario (US-XXX) con sus criterios de aceptación. Sirve igual para cualquier otro artefacto que tenga criterios con identificador codificado — el formato es indiferente (AC-001, 1.1, R-3…) y se usa verbatim, sin normalizar (ver [Tipos de trabajo y criterios](#tipos-de-trabajo-y-criterios)). Es el mismo contrato que produce test-define.
Qué hace: lee, mapea, obtiene los resultados de pruebas delegando en
quality-checky reporta. Es una actividad de verificación, no de desarrollo.
No ejecuta pruebas por sí mismo. La ejecución de la batería de pruebas se delega enquality-check: si existe una corrida previa fresca dequality-check(sin cambios en el código desde entonces), se reutilizan sus resultados; si no, se invocaquality-checken modotests-onlypara producirlos. Ver [Resultados de pruebas: delegación en quality-check](#resultados-de-pruebas-delegación-en-quality-check).
Reporte idempotente. Si no han cambiado ni el código, ni las pruebas, ni los criterios y casos de prueba del artefacto desde la última vez que se generó elcoverage.md, no se genera un documento nuevo: se devuelven los mismos resultados del reporte existente. Ver [Reutilización del reporte (idempotencia)](#reutilización-del-reporte-idempotencia).
Qué NO hace: no escribe ni modifica código de aplicación, no escribe nuevos tests (eso es dequality-specialistvíawork-implement), no edita la especificación de producto (README de la US,TK-XXX,WI-XXX,FT-XXX,validation.md, ADRs), ni corre la suite de pruebas directamente. Lo único que produce es el reporte de trazabilidad. Lo que no se puede determinar de las fuentes va a Observaciones o se pregunta al usuario — nunca se inventa cobertura ni resultados.
Alcance del informe
El informe de este skill cubre un artefacto concreto y sus criterios de aceptación. La pregunta es «¿cada criterio de este trabajo está probado?», así que el universo lo definen los criterios del artefacto, no los archivos que cambiaron ni el repositorio completo.
Consecuencias prácticas:
- Se validan todos los criterios del artefacto, aunque en esta rama no se haya tocado el código de alguno de ellos: un criterio cuya prueba nunca se escribió sigue siendo un hueco.
- No se reportan pruebas ni código ajenos al artefacto. Tests de otros trabajos, cobertura global o fallos en módulos que no mapean a ningún criterio de este artefacto no entran en la matriz — a lo sumo van a «Observaciones y pendientes».
- Si la rama abarca varios trabajos, se valida uno por corrida, con su propio
coverage.mdjunto a su artefacto. Los resultados de pruebas sí son compartidos (vienen de la corrida dequality-check), pero el mapeo es por artefacto. - La clave de frescura tiene una mitad de rama y otra de artefacto. El
FINGERPRINTcubre el código y los tests de todo el árbol, así que un cambio en otro trabajo de la misma rama invalida también estecoverage.md; elSPEC_FINGERPRINTcubre solo la carpeta de este artefacto. Es conservador a propósito: prefiere revalidar de más antes que devolver un reporte que ya no corresponde.
Subagente
Si el proyecto define el subagente quality-specialist, ejecutar este skill bajo ese subagente (es el mismo agente que escribe los tests en el cierre de work-implement, por lo que es el contexto natural para validarlos). Si no existe en el proyecto, ejecutar el flujo normalmente.
Tipos de trabajo y criterios
El tipo se determina por el identificador que indique el usuario o por la ruta de trabajo. Cada tipo fija de dónde se leen los criterios de aceptación y con qué códigos se traza.
| Tipo | Identificador | Dónde viven los criterios | Códigos a trazar |
|---|---|---|---|
| Historia de usuario | US-XXX |
Sección Criterios de aceptación del README.md de la US (lista plana, habitualmente AC-XXX) |
El identificador de cada criterio, en el orden en que aparecen |
| Tarea de mantenimiento | WI-XXX |
Sección ## Criterios de aceptación del README.md del WI (WI-XXX-[kebab]/README.md) |
El identificador de cada criterio, en el orden en que aparecen |
| Feature (funcionalidad ya implementada) | FT-XXX |
Sección ## Criterios de aceptación del README.md del feature (docs/specs/features/FT-XXX-[slug]/README.md) |
El identificador de cada criterio, en el orden en que aparecen |
| Cualquier otro artefacto de especificación | Ruta o nombre que indique el usuario | La sección de criterios del documento (puede llamarse «Criterios de aceptación», «Requisitos», «Acceptance Criteria»…) | El identificador de cada criterio, tal como aparece |
El requisito no es el formato, es que exista identificador. En todo el flujo, «criterio» se refiere al identificador tal como está escrito en el artefacto —
AC-012,1.3,R-3,CA-07son todos válidos. Nunca normalizar ni renombrar: el vínculo de trazabilidad debe ser buscable literalmente tanto en el artefacto como en los TCs que produjotest-define. Si el trabajo no tiene criterios, o los tiene sin identificador, no hay nada que trazar → bloquear (ver «Cuándo bloquear»).
FT — validar cobertura de funcionalidad ya implementada. Un
FT-XXXes el
registro de una funcionalidad ya implementada (inferida de código legacy por el
análisis dework-research, o simplemente el registro de funcionalidad existente),
no trabajo por construir. Validarlo responde: *¿esa funcionalidad ya existente está
cubierta por pruebas?* Un criterioUNCOVEREDsignifica que ese comportamiento
carece de pruebas (un hueco a cerrar escribiendo tests), no que falte código
funcional. Sus casos de prueba documentados viven endocs/specs/features/FT-XXX-[slug]/test-cases/, igual que en una US o un WI.
Modificadores de invocación
Las claves son en inglés (estándar); el usuario puede nombrarlas en español y se mapean. Sin modificador, se asume el comportamiento por defecto.
| Modifier | Efecto exacto |
|---|---|
revalidate |
Forzar la regeneración del coverage.md aunque el existente esté fresco: ignorar la comprobación del Paso 0 y ejecutar el flujo completo. Sinónimos aceptados: «revalidar», «forzar», «vuelve a validar». Necesario cuando los criterios viven fuera del repo (un ticket, un documento externo) y han cambiado allí — eso el SPEC_FINGERPRINT no puede verlo. Mismo modificador y mismo significado que en [code-review](../code-review/SKILL.md). |
Cómo preguntar al usuario
Mecanismo, ritmo y fallback compartidos: [../../reference/asking.md](../../reference/asking.md).
Cada vez que este skill o sus referencias digan preguntar, pedir, confirmar, validar o sugerir algo al usuario, asume ese mecanismo; no se repite allí.
Resolución de idioma
Antes de ejecutar este skill, DEBES leer [../../reference/language.md](../../reference/language.md).
Las reglas de language.md son obligatorias y tienen prioridad para determinar el idioma de todos los artefactos y mensajes generados por este skill.
No continúes hasta haber leído y aplicado language.md.
Excepción deliberada: la salida y los mensajes de error de las herramientas de prueba no se traducen; se citan literales.
Información requerida antes de generar el reporte
No inventar nada. Si un dato no es explícito, obtenerlo del repo o preguntar al usuario.
| Dato | Cómo obtenerlo | Si no está disponible |
|---|---|---|
| Trabajo a validar | Indicado por el usuario o inferido de la ruta de trabajo; determinar el tipo (US-XXX / WI-XXX / FT-XXX / otro artefacto) |
Preguntar qué trabajo validar; sin él no se puede generar el reporte |
| Criterios de aceptación | Según el tipo (ver [Tipos de trabajo y criterios](#tipos-de-trabajo-y-criterios)) | Si el trabajo no tiene criterios de aceptación: bloquear y reportar — sin criterios no hay nada que trazar |
| Casos de prueba | Fuente primaria: la carpeta test-cases/ junto al artefacto y su índice test-cases/README.md, más la línea Casos de prueba: que test-define deja bajo cada criterio. Fallback: inferir desde los tests del repo |
Si no hay casos documentados, derivar la cobertura desde los artefactos de prueba del repo |
| Artefactos de prueba | Buscar en el repo archivos de test unit / integración / e2e relacionados con el trabajo (ver el Paso 2 en references/flow.md) |
Si no se encuentran, marcar criterios sin artefacto como UNCOVERED y dejar Observación |
| Resultados de pruebas | Delegados en quality-check: caché fresca test-run.json o invocación tests-only (ver [Resultados de pruebas: delegación en quality-check](#resultados-de-pruebas-delegación-en-quality-check)) |
Si quality-check no puede ejecutarlas (sin stack, entorno sin correr, no disponible en la sesión) o el usuario declina la delegación: las filas con artefacto van con Ejecución = — y Resultado = NOT_RUN`, y el motivo a «Observaciones y pendientes» |
| Alcance | Todo el trabajo por defecto; el usuario puede acotar a ciertos criterios | Si es ambiguo, preguntar |
Leer siempre el documento de criterios completo (el
README.mddel trabajo, o el archivo del artefacto externo) antes de generar el reporte. No asumir criterios que no estén escritos.
Flujo
Resumen de los pasos. El detalle íntegro de cada paso está en references/flow.md (leerlo antes de ejecutar el flujo).
- Comprobar frescura del reporte — si ya existe
coverage.mdcon un fingerprint guardado y no hubo cambios en los archivos desde entonces, devolver el reporte existente sin regenerarlo (ver [Reutilización del reporte (idempotencia)](#reutilización-del-reporte-idempotencia)). Solo si hay cambios (o el usuario pide revalidar) continuar con los pasos siguientes. - Localizar y leer el trabajo — resolver tipo y ubicación; extraer todos los criterios con su identificador verbatim. Sin criterios (o sin identificador) → bloquear (ver «Cuándo bloquear»).
- Inventariar casos y artefactos — leer la carpeta
test-cases/del artefacto y su índice como fuente primaria, y clasificar los tests del repo por tipo, con ruta y criterio. - Mapear cobertura fila a fila — expandir cada criterio en sus filas (criterio × TC × tipo declarado), rellenar
Evidenciay derivar el estado del criterio (ver «Estados de cobertura») con sus observaciones. No forzar mapeos inciertos. - Obtener resultados de pruebas (delegando en
quality-check) — reutilizar la cachétest-run.jsonsi está fresca, o invocarquality-checken modotests-only; mapear por suite a las filas y rellenarEjecución(quality-check/Manual/—) yResultado(PASS/FAIL/NOT_RUN/UNCOVERED/N/A). No correr pruebas directamente. Nunca fabricar resultados (ver [Resultados de pruebas: delegación en quality-check](#resultados-de-pruebas-delegación-en-quality-check) yreferences/flow.md). - Redactar el reporte desde
assets/coverage-template.md(leerla antes de redactar): cabecera, Resumen (prosa con la procedencia + tabla de indicadores), cobertura por criterio (una fila por criterio, con su Estado), matriz de trazabilidad (una fila por criterio × TC × tipo declarado, con Evidencia, Ejecución y Resultado) y, si los hay, los caveats globales en «Observaciones y pendientes». Ver [Vistas del reporte](#vistas-del-reporte-cobertura-por-criterio-y-matriz). - Emitir el veredicto (ver «Veredicto») respondiendo si todos los criterios quedan cubiertos.
- Entregar y guardar el reporte en la ubicación del tipo (ver «Ubicación de archivos»), grabando el fingerprint del estado actual para la próxima comprobación de frescura; no modificar otros artefactos.
Vocabulario de veredictos y estados
Antes de redactar cualquier informe, DEBES leer [../../reference/verdicts.md](../../reference/verdicts.md).
Las reglas de verdicts.md son obligatorias: el valor canónico y el símbolo son estables, y la etiqueta que lee la persona se redacta siempre en el idioma resuelto por language.md. Ninguna etiqueta de este skill se fija en un idioma concreto.
No continúes hasta haber leído y aplicado verdicts.md.
Estados de cobertura
Los valores de la columna Estado son canónicos: en el reporte se escribe su símbolo seguido de la etiqueta en el idioma resuelto.
| Estado (canónico) | Símbolo | Cuándo aplicarlo |
|---|---|---|
COVERED |
✅ |
El criterio tiene al menos un caso de prueba y el artefacto que le corresponde, y lo valida de forma completa. Si se ejecutó automáticamente, pasó. Un criterio cuyos TCs son Manual por diseño también es COVERED si esos TCs lo validan por entero — ver la nota de abajo. |
PARTIAL |
⚠️ |
El criterio está cubierto solo en parte: hay prueba pero no abarca todo el criterio, el artefacto existe pero no se pudo ejecutar, el resultado fue parcial, existe solo validación manual no declarada como tal (TC automatizable aún sin automatizar), o la suite que agrupa su test dio FAIL pero no se pudo aislar si el test específico del criterio fue el que falló (ver «Mapeo a la matriz» más abajo). Detallar el límite en Observaciones. |
UNCOVERED |
❌ |
No existe caso de prueba ni artefacto que valide el criterio, o la prueba asociada falló y se pudo aislar que fue la suya. |
Cobertura ≠ ejecución. Que exista prueba que valida el criterio es una cosa; que haya corrido y con qué resultado, otra. Un criterio cuya prueba falló —y se pudo aislar que fue la suya— se reporta
UNCOVEREDcon el fallo en Observaciones; si la suite falló pero no se puede aislar el test, esPARTIAL(ver «Mapeo a la matriz»).
Elstatusdel TC filtra la cobertura. La fuente primaria es la columnaEstadodel índicetest-cases/README.md; si el índice no la trae, abrir elTC-XXX-*.mdy leer su campoEstado, con la marca oculta<!-- tc:status=Draft|Ready|Obsolete · testType=… -->como desempate. Los valores (Draft/Ready/Obsolete) son canónicos y no se traducen; lo que va en el idioma resuelto es la etiqueta del campo. Un TCObsoleteno cuenta como cobertura (dejar Observación); unoDraftcuenta como coberturaPARTIAL(aún no está listo para respaldar el criterio); solo losReadycuentan como cobertura plena. Si el TC no trae el campo, tratarlo comoReady. Esto es distinto delEstado:del artefacto, que este skill no exige (ver «Cuándo bloquear»).
Manual por diseño vs. pendiente de automatizar.test-definedistingue los dos casos en el campo Tipo de prueba del TC:Manualsignifica no se automatiza por decisión de diseño; cualquier otro valor (Unit,Integration,API Test,Visual Test,E2E) significa debería existir artefacto automatizado. Respetar esa declaración: un criterio con TCsManualque lo cubren por completo esCOVERED(sus filas van conEjecución = ManualyResultado = N/A), no una deuda; un criterio con TCs automatizables sin artefacto esPARTIALoUNCOVERED. No penalizar una decisión de diseño ni disimular una automatización pendiente.
Un TC con varios tipos declarados se cubre por tipo. Si un TC declaraUnit, E2Ey solo existe el test unitario, el criterio no esCOVERED: la filaE2Ede la matriz queda enUNCOVEREDy el criterio baja aPARTIAL, con el tipo faltante nombrado en Observaciones. La matriz muestra esa asimetría fila a fila (ver [Vistas del reporte](#vistas-del-reporte-cobertura-por-criterio-y-matriz)).
Vistas del reporte: cobertura por criterio y matriz
El reporte tiene dos tablas complementarias, no una. Separarlas evita el problema de meter en una sola fila información de granularidades distintas (un criterio puede tener varios TCs, y un TC varios tipos de prueba).
El Resumen las precede con una tabla de indicadores de cuatro columnas y una sola fila de cifras —criterios de aceptación, cubiertos, parciales, no cubiertos— cuyos tres últimos valores deben sumar el total. No lleva indicadores de pruebas (fallidas, no ejecutadas): esa granularidad ya está en la matriz y mezclar los dos ejes confunde. La procedencia de los resultados y el result por suite van en la línea «Pruebas» del Resumen; test-run.json no trae un agregado global, así que no se inventa uno.
1. Cobertura por criterio — la vista de veredicto. Una fila por criterio:
| Criterio | Descripción | Estado | Observaciones |
|---|---|---|---|
| AC-2.1 | El usuario recibe confirmación por correo | PARTIAL |
E2E declarado en TC-001 sin automatizar |
| AC-2.2 | La plantilla del correo respeta la identidad visual | COVERED |
Validación manual por diseño (TC-004) |
2. Matriz de trazabilidad — la vista auditable. Una fila por cada combinación criterio × TC × tipo de prueba declarado: si un TC declara Unit, E2E, produce dos filas.
| Criterio | TC | Tipo | Evidencia | Ejecución | Resultado |
|---|---|---|---|---|---|
| AC-2.1 | TC-001 | Unit | tests/unit/notify.test.ts |
quality-check | Paso |
| AC-2.1 | TC-001 | E2E | — | — | UNCOVERED |
| AC-2.2 | TC-004 | Manual | test-cases/TC-004-revision-visual.md |
Manual | N/A |
Semántica de las columnas:
| Columna | Qué contiene | Valores |
|---|---|---|
| Criterio | Identificador verbatim del artefacto, repetido en cada fila suya | AC-012, 1.3, R-3… |
| TC | Caso de prueba que produjo test-define |
TC-XXX · — si el criterio no tiene TC documentado (fila derivada de un test hallado, o hueco total) |
| Tipo | El Tipo de prueba declarado en el TC; en filas derivadas, el tipo del artefacto hallado |
Manual · Unit · Integration · API Test · Visual Test · E2E · — (sin TC y sin artefacto) |
| Evidencia | La prueba concreta que respalda la fila | Ruta del artefacto automatizado · ruta del TC para filas Manual · — si esa intención no está materializada |
| Ejecución | Quién produjo el resultado | quality-check · Manual · — (no se ejecutó) |
| Resultado | Qué dio esa prueba. Valores canónicos; en el reporte va la etiqueta en el idioma resuelto | PASS · FAIL · NOT_RUN (hay artefacto, no corrió) · UNCOVERED (no hay evidencia para ese tipo) · N/A (manual por diseño) |
Por qué se eliminó la columna
Automática. UnSíno decía nada útil: no revelaba qué tipo de prueba
respaldaba el criterio, dónde vivía, ni quién produjo el resultado.Tipo+Evidencia+Ejecucióndan
esa información sin ambigüedad, y la granularidad por tipo hace visible el hueco (la filaE2Esin
evidencia) en lugar de esconderlo tras unSíque solo hablaba del test unitario.
Evidencia = —implicaEjecución = —yResultado =UNCOVERED`. No hay excepción: si no hay
artefacto, no hubo ejecución ni puede haber resultado. Al revés no: puede haber evidencia conEjecución = —yResultado =NOT_RUN(el artefacto existe peroquality-check` no pudo correrlo;
la razón va a «Observaciones y pendientes»).
Criterio sin TC documentado pero con test hallado. Si el mapeo se infirió desde el repo (fallback del
Paso 2), la fila se escribe igual conTC = —y el tipo del artefacto hallado, y se anota en
Observaciones que el mapeo es inferido, no declarado. Solo el criterio sin TC y sin artefacto produce
la fila vacía— | — | — | — |UNCOVERED`.
Derivación del Estado del criterio a partir de sus filas. Evaluar en orden y detenerse en la primera que aplique:
| # | Filas del criterio | Estado |
|---|---|---|
| 1 | Ninguna fila aporta cobertura — todas en UNCOVERED, o el criterio no tiene TC ni artefacto, o sus únicos TCs son Obsolete — o alguna fila dio FAIL aislado a su test |
UNCOVERED |
| 2 | Alguna fila en UNCOVERED/NOT_RUN, algún TC en Draft u Obsolete conviviendo con cobertura válida, o un FAIL de suite no aislable |
PARTIAL |
| 3 | Todas con Resultado ∈ {PASS, N/A} y todos los TCs en Ready (o sin campo Estado) |
COVERED |
Dos destinos de observación, no intercambiables. La prueba para elegir: *¿se puede atribuir a un
criterio concreto?* Si sí, va en la columnaObservacionesde la tabla 1; si no, en la **sección
«Observaciones y pendientes»**. La matriz no lleva columna de observaciones.
| Destino | Qué recibe |
|---------|------------|
| ColumnaObservaciones(tabla 1) | Tipo declarado sin automatizar · TC enDraft/Obsolete·FAILno aislable · suite efectiva distinta del tipo declarado · mapeo inferido en vez de declarado · cobertura apoyada en TCsManual(aunque sea por diseño: es el caveat que justifica elAPPROVEDWITHNOTES) · límite de la cobertura |
| Sección «Observaciones y pendientes» | SuitecoverageenFAIL·workingTreeClean: false(árbol sucio) · clases de prueba ausentes en el repo · ejecución no delegable y su motivo · tests que no se pudieron vincular con certeza a ningún criterio · tests o fallos ajenos al artefacto |
La sección global se omite entera si no hay ninguno. Cuando el skill diga «dejar Observación» sin más,
aplicar esta prueba.
La derivación no es cerrada sobre la matriz: dos datos viven fuera de ella. (a) el
Estadodel TC
(Draft/Obsolete/Ready, que viene del propio TC) y (b) si unFAILpudo aislarse al test del
criterio. Ambos se anotan siempre en la columna Observaciones de la tabla 1 — sin esa anotación, dos
criterios con filas idénticas quedarían con estados distintos sin explicación. UnFAILno aislable se
escribe igual (Resultado = FAIL) en la matriz; lo que lo distingue es la Observación «suiteXenFAIL, no se pudo aislar el test» y elEstado =PARTIAL` resultante.
TCsObsolete. Sus filas se conservan en la matriz por trazabilidad con su valor real, pero **no
cuentan como cobertura** al derivar el estado: si son los únicos TCs del criterio, este cae en la fila 1
aunque sus filas diganPASS; si conviven con TCsReadyque sí lo cubren, el criterio es como máximoPARTIAL(fila 2). En ambos casos, Observación explicando que el TC está obsoleto.
Reutilización del reporte (idempotencia)
Mismo principio de caché que quality-check y [code-review](../code-review/SKILL.md#reutilización-del-informe-idempotencia) —las tres puertas del cierre lo aplican, cada una sobre su propio artefacto—: si no hubo cambios en los archivos desde la última generación, no se produce un reporte nuevo — se devuelven los mismos resultados del coverage.md existente. Esto evita rehacer el mapeo y volver a delegar la ejecución de pruebas cuando nada cambió.
Contexto de ejecución. Como
quality-check, este skill es una compuerta de cierre (al integrar o
antes del PR), no corre por tarea ni durante la implementación. La frescura se evalúa sobre la rama
consolidada del cierre. En el pipeline típico de cierrepr-createcorrequality-checkprimero
(producetest-run.jsonfresco) y luegotrace-validate, que reutiliza esa corrida — sin doble
ejecución de pruebas; y si el código tampoco cambió desde el últimocoverage.md, este Paso 0 lo
devuelve sin regenerarlo.
Clave de frescura — dos hashes, porque el reporte depende de dos cosas distintas.
| Clave | Qué cubre | Cómo se calcula |
|---|---|---|
FINGERPRINT |
El código y los tests. El fingerprint canónico de la tubería, idéntico al de quality-check y code-review: excluye toda carpeta oculta, cualquier docs/ y los coverage.md sueltos, para que escribir un artefacto generado no invalide la caché. Receta exacta en [quality-check](../quality-check/SKILL.md#caché-de-corrida-de-pruebas-compartida-con-trace-validate). |
Sobre todo el árbol, menos las exclusiones |
SPEC_FINGERPRINT |
Los criterios y los casos de prueba del artefacto que se valida: su README.md y su carpeta test-cases/. Viven bajo docs/specs/, que el FINGERPRINT excluye — sin esta segunda clave, reescribir un criterio no invalidaría nada. |
Sobre la carpeta del artefacto, excluyendo su propio coverage.md |
bash NOREPORT=":(exclude)${ARTEFACTO%/}/coverage.md" SPECFINGERPRINT=$( { git -C "$ROOT" ls-files -s -- "$ARTEFACTO" "$NOREPORT"; \ git -C "$ROOT" status --porcelain -uall -- "$ARTEFACTO" "$NOREPORT"; \ git -C "$ROOT" diff -- "$ARTEFACTO" "$NO_REPORT"; \ } | git hash-object --stdin )
donde $ARTEFACTO es la carpeta del trabajo (docs/specs/user-stories/US-042-…/) o, si el artefacto es un archivo suelto, su ruta. Se reutiliza el reporte solo si coinciden los dos.
La exclusión del propio reporte no es opcional. El
coverage.mdvive dentro de$ARTEFACTO: sin$NOREPORT, escribirlo en el Paso 7 movería elSPECFINGERPRINT, la marca de pie guardaría el hash de antes de escribir, y ninguna corrida posterior coincidiría — la idempotencia no se dispararía nunca. La clave cubre las entradas del reporte, no su salida; es el mismo motivo por el que elFINGERPRINTexcluye**/coverage.md.
Y tiene que ser una ruta literal interpolando$ARTEFACTO, no un glob.':(exclude,glob)/coverage.md'junto a un pathspec positivo hace que git excluya todo**: las tres órdenes devuelven vacío, la clave queda fija en el hash del blob vacío, y entonces la idempotencia se dispara siempre y un criterio editado nunca invalida el reporte. ElEXCdelFINGERPRINTpuede usar globs porque ahí no hay pathspec positivo.
Por qué dos claves y no una. Meter
docs/entero en elFINGERPRINTharía que escribir cualquier informe invalidara las tres cachés — el problema que las exclusiones resuelven. Acotar la segunda clave a la carpeta del artefacto captura exactamente lo que este reporte traza, sin arrastrar el resto de la documentación. Y a diferencia de «detectar que el usuario editó los criterios», es una comprobación determinista: no depende de que el cambio haya ocurrido en esta sesión, ni de que alguien lo mencione.
Lo que sigue sin cubrirse: criterios que viven fuera del repo (un ticket de un tracker, un documento externo). Ahí no hay nada que hashear; si el artefacto es externo, decirlo en el reporte y pedir
revalidatecuando cambie.
Un solo cálculo por corrida, con una excepción. Ambos hashes se computan una vez, en el Paso 0. El
FINGERPRINTsirve para las dos comprobaciones de frescura —la delcoverage.md(Paso 0) y la deltest-run.json(Paso 4, delegación)—; elSPEC_FINGERPRINTsolo para la primera. Los dos se regraban en el
Paso 7. Si hubo delegación entests-only, recalcular elFINGERPRINTantes de grabar: esa corrida no
toca código, pero sí puede normalizar el.gitignorela primera vez quequality-checkcorre en el repo, y
eso mueve la clave. ElSPEC_FINGERPRINTno se ve afectado.
Comportamiento (Paso 0 del flujo):
- Resolver la ubicación del trabajo y calcular
FINGERPRINTySPEC_FINGERPRINT. Siempre, haya reporte
previo o no: el Paso 7 los necesita para grabar la marca de pie, también en la primera validación.
- Buscar su
coverage.md. Si no existe → generar normal (no hay caché). - Si existe, leer los hashes guardados en su marca de pie
(<!-- trace-validate:verdict=<canónico> · fingerprint=<hash> · spec=<hash> · generated=YYYY-MM-DD -->) y reutilizarlo solo si se cumple todo: coinciden los dos hashes, el reporte no registra una ejecución fallida, y el usuario no pasó revalidate. - Se cumple → no regenerar: devolver el veredicto y el resumen del reporte existente tal cual, e indicar al usuario que no hubo cambios desde la última validación ({{fecha guardada}}). No reescribir el archivo, no delegar en quality-check. - Falla algo, no hay marca de pie (reportes antiguos), o el usuario pide revalidate → ejecutar el flujo completo (Pasos 1-7) y regrabar ambos hashes al guardar (Paso 7).
- La marca de pie se conserva en el documento publicado (no se elimina como el bloque de instrucciones
de la plantilla). Si está ilegible o incompleta (un hash que no parsea, marca truncada, o falta el campo spec=), no intentar repararla ni adivinar: tratar la caché como ausente, regenerar y regrabarla.
Un reporte que no pudo ejecutar las pruebas nunca se sirve desde caché. Si el reporte existente tiene
filas enNOT_RUNporque la delegación no fue posible (sin red, sin runner, el usuario declinó), su⚠️describe un fallo de entorno, no del código. Congelarlo significaría arrastrar ese «no se pudo
comprobar» para siempre aunque el entorno ya funcione. Regenerar y volver a intentar la delegación.
Un cambio en una carpeta oculta (
.sdd-devkit/,.github/…), endocs/fuera de la carpeta del
artefacto, o en uncoverage.mdno cuenta como cambio: están excluidos, así que ningún artefacto
que generen este skill,quality-check,code-reviewoarch-auditdesplaza la clave. Los criterios y losTC-XXXsí cuentan, víaSPEC_FINGERPRINT.
Resultados de pruebas: delegación en quality-check
trace-validate no ejecuta la suite de pruebas. La ejecución es responsabilidad de quality-check, que la persiste en un artefacto reutilizable test-run.json (esquema test-run/v1). Como el review es una corrida completa de la rama, este artefacto vive en una ubicación fija, no por unidad: .sdd-devkit/test-run.json, en la raíz del repositorio.
Cómo obtener los resultados (Paso 4 del flujo):
- Reusar el fingerprint canónico ya calculado en el Paso 0 (mismo valor; no recalcular).
- **Si existe
test-run.json, suschemaestest-run/v1, sugeneratedByes"quality-check", sugit.fingerprintcoincide y su
suites[] cubre el conjunto de suites vigente (las dos fijas, más e2e si el repo la ejecuta y las que declare el estándar de testing) → caché fresca: no hubo cambios desde la corrida de quality-check. Reutilizar los resultados por suite sin ejecutar nada. Si generatedBy trae cualquier otro valor, descartar la caché y delegar: quality-check es el único productor autorizado. Si el estándar de testing cambió desde la corrida (suites de más o de menos), la caché es obsoleta aunque el fingerprint coincida —el estándar vive en docs/, excluido del fingerprint—: delegar. Anotar la procedencia en la línea «Pruebas» del Resumen**: «resultados tomados de la corrida de quality-check del {{commit/fecha}}».
- Si no existe o el fingerprint difiere (hubo cambios, o nunca corrió) → **delegar en
quality-check
en modo tests-only**, que ejecuta solo los checks de pruebas, escribe test-run.json y devuelve los resultados. Luego consumir esa caché ya fresca.
- Si
quality-checkno puede ejecutarlas (stack no detectable, entorno sin poder correr, dependencias
ausentes, o el usuario declina la delegación) → las filas con artefacto van con Ejecución = — y Resultado = NOT_RUN`, con la razón en «Observaciones y pendientes», y se entrega igualmente la matriz con los artefactos hallados. Nunca fabricar resultados.
Mapeo a la matriz. Cada entrada suites[] de test-run.json trae type y result (PASS/FAIL/SKIPPED/N/A). Las dos fijas —unit, coverage— vienen siempre; e2e solo si el repo la ejecuta, y el resto son suites configuradas en el estándar de testing del repo, cuyo type es el ID del requisito que las declara (p. ej. integration-testing, contract-testing) y que traen su referencia global en standard (p. ej. testing/integration-testing). Pueden no existir: si el estándar no declara integración, no hay entrada para ella —y no hay que buscar una clave fija llamada integration—, así que una fila de tipo Integration se resuelve contra la suite donde el repo la tenga (típicamente unit) o queda NOTRUN. No inferir una suite ausente ni inventar su resultado. La suite coverage no se mapea a ningún criterio: es cobertura de líneas/ramas, una métrica del repo que juzga quality-check, no cobertura funcional; si viene en FAIL, mencionarlo en «Observaciones y pendientes» y nada más. Mapeo al reporte: PASS→PASS, FAIL→FAIL, SKIPPED→NOTRUN, N/A (el repo no tiene esa suite)→NOT_RUN, dejando en «Observaciones y pendientes» que esa clase de prueba no existe en el repo. Un criterio cuya prueba asociada dio FAIL y se pudo aislar que fue la suya se reporta UNCOVERED con el fallo en Observaciones; si la suite falló sin poder aislar el test, es PARTIAL (ver «Estados de cobertura» y la nota de granularidad más abajo).
El mapeo es por fila, no por criterio. Cada fila de la matriz (criterio × TC × tipo) se resuelve así:
| Situación de la fila | Evidencia | Ejecución | Resultado |
|---|---|---|---|
| Tipo declarado sin artefacto en el repo | — |
— |
UNCOVERED |
Artefacto hallado y la suite que lo corre dio PASS |
ruta | quality-check |
PASS |
Artefacto hallado y su test dio FAIL (aislable) |
ruta | quality-check |
FAIL |
Artefacto hallado, suite en FAIL sin poder aislar el test |
ruta | quality-check |
FAIL (+ Observación «no aislable» → criterio PARTIAL) |
Artefacto hallado, suite SKIPPED / ausente / no ejecutable |
ruta | — |
NOT_RUN |
TC Manual por diseño |
ruta del TC | Manual |
N/A |
Ejecución dice quién produjo el resultado, no de qué clase es la prueba: eso ya lo dice la columna Tipo y la ruta de Evidencia. La suite efectiva que corrió el test (dónde vive realmente en el repo) solo se menciona cuando no coincide con el tipo declarado —un API Test que corre en unit, por ejemplo—, y va en Observaciones, no en la matriz.
Granularidad suite vs. criterio:
resultes por suite completa, no por test individual. Si
varios criterios mapean a tests dentro de la misma suite y esa suite daFAIL, no propagarFAIL/UNCOVEREDa todos ellos sin más: si elsummaryu otro detalle dequality-checkpermite aislar qué test
falló, marcar solo ese criterio; si no hay forma de aislarlo, marcar los criterios afectados comoPARTIAL(noUNCOVERED) con la ambigüedad explicada en Observaciones. Detalle completo enreferences/flow.md(Paso 4).
Si el proyecto no usa
quality-check(no está disponible en la sesión), degradar con elegancia: reportar
las filas con artefacto enEjecución = —/Resultado =NOT_RUN(«ejecución delegada no disponible») —las que no tienen artefacto siguen enUNCOVERED`— y entregar la cobertura estática. No
reintroducir un runner propio entrace-validate.
Cuándo bloquear
Parar y reportar (sin generar reporte parcial) cuando:
- El trabajo no existe o no se encuentra su documento de criterios.
- No hay sección de criterios de aceptación, está vacía, o los criterios no tienen identificador codificado (el formato es indiferente; lo que no puede faltar es el identificador): no hay nada que trazar de forma trazable; sugerir alinear el trabajo con su skill de definición/planificación antes de validar (para un
FT-XXX, completar su especificación con el flujo «Analizar legado» dework-research).
No bloquear por que el artefacto no siga las convenciones del plugin: identificadores fuera del formato
AC-XXX, ubicación fuera dedocs/specs/o ausencia de campoEstado:no son motivos de bloqueo.
` WARNING No es posible generar el reporte de trazabilidad:
- <razón concreta>
- <acción sugerida: p. ej. definir los criterios de aceptación del trabajo antes de validar>
`
Ubicación de archivos
Layout completo del harness, identificadores y contrato de archivado: [../../reference/artifacts.md](../../reference/artifacts.md).
Lo propio de este skill:
| Rol | Ruta |
|---|---|
| Artefacto a trazar (entrada) | La carpeta de la US-XXX / WI-XXX / FT-XXX; para cualquier otro artefacto, la ruta que indique el usuario |
Casos de prueba documentados (entrada, los produce test-define) |
test-cases/ dentro de la carpeta del artefacto, con su índice test-cases/README.md |
Caché de corrida de pruebas (entrada, la produce quality-check) |
.sdd-devkit/test-run.json (ubicación fija, no por unidad) |
| Reporte de trazabilidad (salida) | coverage.md dentro de la carpeta del artefacto, allí donde se haya resuelto — activa o bajo docs/archive/; para otro artefacto, junto a él (confirmar la ruta con el usuario antes de escribir) |
Un
US/WIarchivado se traza igual. Todo se resuelve relativo a la carpeta encontrada: los criterios, eltest-cases/, la claveSPEC_FINGERPRINTy elcoverage.mdde salida.trace-validatees el único skill que escribe dentro de un artefacto archivado, y solo su propio informe: es un derivado del artefacto, no trabajo nuevo, y revalidar un trabajo ya integrado tiene que seguir siendo posible.
Mensaje al usuario
Solo el veredicto, el resumen de cobertura y lo que el usuario debe saber o decidir (criterios UNCOVERED/PARTIAL, pruebas que fallaron, si no se pudo ejecutar y por qué). No narrar el trabajo en curso («leí el README», «creé el archivo») ni el razonamiento interno. Listar pendientes en viñetas agrupadas por criterio.
Veredicto
| Veredicto (canónico) | Símbolo | Cuándo aplicarlo |
|---|---|---|
APPROVED |
✅ |
Todos los criterios del trabajo en estado COVERED y, si se ejecutaron pruebas automáticas, todas pasaron. |
APPROVEDWITHNOTES |
⚠️ |
Ningún criterio en UNCOVERED, pero hay caveats que el usuario debe conocer: algún criterio en PARTIAL, cobertura apoyada en TCs Manual (aunque sea por diseño), o pruebas que no se pudieron ejecutar y por tanto no confirman nada. Enumerar cada caveat. |
REJECTED |
❌ |
Al menos un criterio en UNCOVERED, o una prueba asociada falló de forma aislable. Listar los criterios faltantes/fallidos. |
Precedencia: REJECTED > APPROVEDWITHNOTES > APPROVED. Es decir, APPROVED exige cero caveats: si hay alguno (criterio PARTIAL, cobertura apoyada en TCs Manual, pruebas no ejecutadas), el veredicto es APPROVEDWITHNOTES (⚠️), no APPROVED (✅).
En el cierre, este
⚠️no bloquea (a diferencia delINCOMPLETEdequality-checkycode-review, que sí):work-integrateypr-createcontinúan mostrando las observaciones al usuario. Por eso cada caveat debe quedar enumerado y ser legible por sí solo — es lo único que el usuario verá antes de integrar.
Handoffs del ciclo
Posición: validación / cierre de calidad — después de work-implement.
| | | |--|--| | Entrada | Trabajo (US-XXX / WI-XXX, u otro artefacto) con criterios de aceptación identificados; código implementado; idealmente tests escritos por quality-specialist en el cierre de work-implement. Resultados de pruebas vía quality-check (caché test-run.json o delegación tests-only). O un FT-XXX (registro de funcionalidad ya implementada — inferida de código legacy o documentada como existente) para comprobar si está cubierta por pruebas. | | Salida | coverage.md en la ubicación del tipo + veredicto sobre la cobertura. | | Veredicto REJECTED (US/WI) | Volver a work-implement (fase de pruebas con quality-specialist) para cubrir los criterios faltantes; revalidar después. | | Veredicto REJECTED (FT) | Hay comportamiento ya implementado sin pruebas: escribir los tests faltantes sobre el código existente (no código funcional) con work-implement en su tipo feature —que automatiza los TC-XXX del FT-XXX— y revalidar. Formalizar ese trabajo como una tarea de mantenimiento (WI-XXX) es opcional y lo decide el usuario. | | Falta funcional en el trabajo | Si la matriz revela que un criterio no es testeable o está mal definido, escalar a la definición/planificación del trabajo — para un FT, a quien lo registró (el flujo «Analizar legado» de work-research u otra fuente de la funcionalidad); no editar la especificación desde aquí. |
Mapa de referencias
| Archivo | Cuándo leerlo |
|---|---|
references/flow.md |
Flujo paso a paso (Pasos 0-7), delegación de la ejecución de pruebas en quality-check (caché test-run.json / tests-only) y checklist completo. Leer antes de ejecutar el flujo. |
references/examples.md |
Ejemplos por tipo (US / WI, sin criterios, sin runner, criterio sin prueba) y anti-patrones. Leer ante dudas de comportamiento. |
assets/coverage-template.md |
Plantilla canónica del reporte de trazabilidad. Leer antes de redactar el reporte. |
Referencias compartidas del plugin
Reglas transversales del catálogo; viven en la raíz del plugin, no en este skill.
- [
../../reference/language.md](../../reference/language.md): Idioma — resolución obligatoria del idioma de artefactos y mensajes. Lectura obligatoria antes de ejecutar el skill. - [
../../reference/asking.md](../../reference/asking.md): Preguntas — mecanismo estructurado, ritmo, fallback. Antes de la primera pregunta. - [
../../reference/artifacts.md](../../reference/artifacts.md): Artefactos — rutas del harness, identificadores, archivado. Al resolver una ruta o calcular un ID.