@spec-wave/cli 0.28.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/api/github-graphql.mjs +37 -0
- package/src/api/github-rest.mjs +21 -0
- package/src/cli.mjs +73 -6
- package/src/commands/audit.mjs +280 -0
- package/src/commands/doctor.mjs +83 -2
- package/src/commands/generate-qa-plan.mjs +421 -0
- package/src/commands/implement.mjs +12 -0
- package/src/commands/merge.mjs +292 -0
- package/src/commands/move.mjs +26 -11
- package/src/commands/order.mjs +42 -0
- package/src/commands/qa-run.mjs +813 -0
- package/src/commands/run.mjs +9 -4
- package/src/config.mjs +17 -1
- package/src/lib/artifact-pr.mjs +2 -0
- package/src/lib/board.mjs +18 -2
- package/src/lib/critique.mjs +98 -13
- package/src/lib/decomposition-doc.mjs +5 -1
- package/src/lib/doc-paths.mjs +5 -2
- package/src/lib/next-step.mjs +15 -3
- package/src/lib/pr-step.mjs +12 -7
- package/src/lib/qa-exec.mjs +314 -0
- package/src/lib/qa-plan-doc.mjs +340 -0
- package/src/lib/qa-report.mjs +340 -0
- package/src/lib/spec-audit.mjs +372 -0
- package/src/lib/tech-context.mjs +20 -14
- package/src/plugin/.claude-plugin/plugin.json +1 -1
- package/src/plugin/skills/audit/SKILL.md +34 -0
- package/src/plugin/skills/audit/model-prompt.critique.md +34 -0
- package/src/plugin/skills/merge/SKILL.md +34 -0
- package/src/plugin/skills/order/SKILL.md +1 -0
- package/src/plugin/skills/plan/model-prompt.md +1 -0
- package/src/plugin/skills/plan/reference/tech-context.md +6 -0
- package/src/plugin/skills/preparar-feature/SKILL.md +3 -1
- package/src/plugin/skills/preparar-specs/SKILL.md +21 -1
- package/src/plugin/skills/preparar-specs/reference/revisao.md +5 -2
- package/src/plugin/skills/qa/SKILL.md +105 -0
- package/src/plugin/skills/qa/model-prompt.critique.md +44 -0
- package/src/plugin/skills/qa/model-prompt.md +68 -0
- package/src/templates/config/tech_context.yml +13 -0
- package/src/templates/skill/SKILL.md +77 -4
- package/src/templates/workflows/generate-qa-plan.yml +64 -0
- package/src/templates/workflows/qa.yml +9 -1
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spec-wave-qa
|
|
3
|
+
description: "Use para a etapa 🧪 QA do spec-wave — gerar o plano de QA de uma Feature (label spec-wave:qa → qa-plan.md), revisá-lo, e EXECUTAR os cenários localmente com `spec-wave qa <issue>` (Feature, Story ou Bug). Verde move o board sozinho; vermelho abre um Bug por cenário reprovado. Gatilhos: 'rodar o QA', 'validar a feature 12', 'gerar o plano de QA', 'testar a story 34', 're-testar o cenário 2'."
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Bash(npx @spec-wave/cli@latest qa *)
|
|
6
|
+
- Bash(npx @spec-wave/cli@latest generate-qa-plan *)
|
|
7
|
+
- Bash(npx @spec-wave/cli@latest doctor)
|
|
8
|
+
- Bash(gh issue *)
|
|
9
|
+
- Read
|
|
10
|
+
- Write
|
|
11
|
+
- Edit
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# spec-wave qa — etapa 🧪 QA
|
|
15
|
+
|
|
16
|
+
Duas metades, em ordem obrigatória:
|
|
17
|
+
|
|
18
|
+
1. **Gerar o plano** (label + Action): `spec-wave:qa` na **Feature** → o Action gera `docs/features/<slug>/qa-plan.md`, valida, critica e aplica `spec-wave:qa-ready`.
|
|
19
|
+
2. **Executar** (sempre local): `npx @spec-wave/cli@latest qa <issue>` roda os cenários contra o checkout e emite o veredito.
|
|
20
|
+
|
|
21
|
+
**Nunca rode o `qa` sem a `spec-wave:qa-ready` na Feature** — o comando recusa, e o motivo é de desenho (D-QA3/D-QA4): o veredito **verde avança a Etapa sozinho, sem confirmação humana**, então o portão humano é a **revisão do plano**, antes de executar.
|
|
22
|
+
|
|
23
|
+
## 0. Detecção de configuração (antes de qualquer coisa)
|
|
24
|
+
|
|
25
|
+
Confirme que existe `.spec-wave.json` no repositório (senão → skill **setup**). Para executar de fato, o comando do executor precisa estar em `qa.command` no `.spec-wave.json` (ou na env `SPEC_WAVE_QA_CMD`, que tem precedência):
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"qa": {
|
|
30
|
+
"command": "claude -p \"Execute o QA descrito em {contextFile}\"",
|
|
31
|
+
"setup": "npm ci && npm run build",
|
|
32
|
+
"env": { "BASE_URL": "http://localhost:3000" },
|
|
33
|
+
"defaultBugPriority": "P2"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Placeholders: `{contextFile} {qaPlanFile} {specFile} {issue} {type} {title}`. Sem `qa.command`, o comando monta o contexto, imprime como configurar e **não executa** — não é erro.
|
|
39
|
+
|
|
40
|
+
## 1. Gerar o plano (Feature)
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
gh issue edit <feature> --add-label "spec-wave:qa"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
- **Só em Feature** (D-QA1: o plano é por Feature, arquivo único, seções `## Cenário N — Story #X`). Numa Story o Action comenta apontando a Feature-pai; num Bug, não se aplica (ver §5).
|
|
47
|
+
- Arquivo **ausente** → gera via IA e publica em Pull Request. Arquivo **presente** → valida + critica **COMO ESTÁ** (edições manuais são preservadas — mesma semântica do decompose). Para regerar do zero: apague o arquivo e reaplique a label.
|
|
48
|
+
- Requer `spec.md` e `plan.md` já na base.
|
|
49
|
+
- Desfechos: limpo → `spec-wave:qa-ready` + comentário com o resumo; grave → `spec-wave:critique-failed`; reprovas repetidas → `spec-wave:needs-human`.
|
|
50
|
+
|
|
51
|
+
## 2. Revisar e editar o qa-plan.md (o portão humano)
|
|
52
|
+
|
|
53
|
+
Leia o plano com o usuário ANTES de executar. Regras do arquivo:
|
|
54
|
+
|
|
55
|
+
- A estrutura é só `## Cenário N — Story #X`; o corpo aceita markdown livre.
|
|
56
|
+
- **A posição manda, não o número escrito** — inserir um cenário no meio sem renumerar funciona.
|
|
57
|
+
- `Story #X` é obrigatório e precisa ser sub-issue da Feature.
|
|
58
|
+
- `**Critério:**` e `**Esperado:**` são obrigatórios; `**Pré-condições:**` e `**Passos:**` opcionais.
|
|
59
|
+
- Depois de editar, reaplique `spec-wave:qa` para uma nova crítica (o arquivo NÃO é regerado).
|
|
60
|
+
|
|
61
|
+
> ⚠️ O slug vem do **título** da Feature. Renomeá-la depois da geração órfã o arquivo — o comando falha citando o slug órfão.
|
|
62
|
+
|
|
63
|
+
## 3. Executar — SEMPRE `--dry-run` primeiro
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx @spec-wave/cli@latest qa <issue> --dry-run # mostra cenários-alvo e o comando; ZERO escrita no GitHub
|
|
67
|
+
npx @spec-wave/cli@latest qa <issue> # executa de fato
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Mostre ao usuário o contexto montado em `.spec-wave/qa-<n>.md` antes de rodar sem `--dry-run`.
|
|
71
|
+
|
|
72
|
+
Alvos: `qa <feature>` roda todos os cenários das Stories ainda sem `qa-approved`; `qa <story>` só os daquela Story; `qa <bug>` o Teste de Regressão do `bug.md`; `--only <n[,m]>` filtra por número posicional.
|
|
73
|
+
|
|
74
|
+
**PROIBIDO corrigir código durante a execução.** QA não conserta: cenário reprovado vira Bug, e alterar o código no meio invalida o veredito. Se você for o executor (via `qa.command`), siga as instruções do contexto à risca — um cenário por vez, evidência bruta, `blocked` (nunca `fail`) para o que não pôde rodar.
|
|
75
|
+
|
|
76
|
+
## 4. Os três desfechos
|
|
77
|
+
|
|
78
|
+
| Veredito | O que aconteceu | O que fazer |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| ✅ **verde** (todos pass) | `qa-approved` aplicada; Story → 📋 Homologação; Feature move quando TODAS as Stories liberarem; Bug → 🚀 Deploy | Nada — o board já andou. Se a Story tinha **Bug filho aberto**, ela NÃO avança (guarda dura): feche o Bug primeiro. |
|
|
81
|
+
| ❌ **vermelho** (algum fail) | 1 Bug por cenário reprovado (filho da Story dona, ✅ Ready, `bug.md` commitado, `bug-approved` aplicada); item fica em 🧪 QA; exit 1 | Corrija os Bugs (skill **implement**) e re-teste (§6). |
|
|
82
|
+
| ⚪ **inconclusivo** (blocked, sem fail) | Ambiente quebrado não é defeito: nada move, nenhum Bug; exit 1 | Destrave o ambiente (seed, serviço fora do ar) e rode de novo. |
|
|
83
|
+
|
|
84
|
+
## 5. Bug — exceção documentada (§2.1 da spec)
|
|
85
|
+
|
|
86
|
+
O QA de um **Bug** usa a seção `Teste de Regressão` do próprio `bug.md` (não há qa-plan). Verde move o Bug para **🚀 Deploy** (D-QA6 — Bug não passa por Homologação).
|
|
87
|
+
|
|
88
|
+
E quando um cenário reprova, o `bug.md` do Bug novo **é escrito pelo comando, sem IA e sem a label `spec-wave:bug`** — exceção explícita à regra "nunca escreva o bug.md à mão": a reprodução, o esperado/obtido e o teste de regressão já existem e são determinísticos (são o cenário + a saída real). O arquivo é commitado e a `spec-wave:bug-approved` aplicada pelo próprio comando. **Não** aplique `spec-wave:bug` nesses Bugs — regeraria por IA um documento que registra uma execução observada.
|
|
89
|
+
|
|
90
|
+
## 6. Ciclo de re-teste
|
|
91
|
+
|
|
92
|
+
1. Fix do Bug (skill **implement**, PR, merge).
|
|
93
|
+
2. Re-teste só o cenário: `npx @spec-wave/cli@latest qa <story> --only <cenário>`.
|
|
94
|
+
3. O comando NÃO duplica Bug: se o cenário reprovar de novo, ele comenta no Bug existente (marcador `spec-wave:qa-origin`).
|
|
95
|
+
4. Verde com o Bug ainda aberto não avança a Story — feche o Bug (o fix mergeado + regressão verde justificam) e rode o `qa` de novo.
|
|
96
|
+
|
|
97
|
+
## Recusas que você vai encontrar (e o que significam)
|
|
98
|
+
|
|
99
|
+
- Sem `.spec-wave.json` → rode a skill **setup**.
|
|
100
|
+
- `spec-wave:qa` ainda na issue → geração em voo; aguarde o Action.
|
|
101
|
+
- `critique-failed`/`needs-human` → portão humano da crítica; corrija o documento apontado.
|
|
102
|
+
- Feature sem `qa-ready` → gere/critique o plano primeiro (§1).
|
|
103
|
+
- Etapa **anterior** a 🧪 QA → o `qa` não promove item; quem move até QA é o merge (`spec-wave merge` / `run --pr`).
|
|
104
|
+
- Etapa **posterior** → informa e sai 0 (a Etapa nunca retrocede).
|
|
105
|
+
- Nenhum cenário casando com a Story → plano desatualizado (re-decompose criou Stories novas) ou Feature renomeada (slug órfão).
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: critique-qa-plan
|
|
3
|
+
action: critique
|
|
4
|
+
description: Critério da crítica adversarial do qa-plan.md contra spec, plan e decomposição, antes da liberação para execução.
|
|
5
|
+
tools: [Read, Glob, Grep]
|
|
6
|
+
maxTurns: 20
|
|
7
|
+
lenses:
|
|
8
|
+
- "cobertura — algum critério de aceite da spec ficou sem cenário correspondente?"
|
|
9
|
+
- "vacuidade — algum cenário passaria mesmo sem a implementação, ou tem esperado não observável?"
|
|
10
|
+
- "fidelidade — algum cenário testa implementação em vez de comportamento, ou contradiz a spec?"
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Crítica adversarial do plano de QA
|
|
14
|
+
|
|
15
|
+
Você audita o `qa-plan.md` proposto contra o `spec.md`, o `plan.md` e a decomposição. Seu papel é encontrar problemas, não elogiar.
|
|
16
|
+
|
|
17
|
+
Este portão importa mais que os outros: o veredito **verde da execução avança a Etapa sozinho, sem confirmação humana** (D-QA3). Um plano fraco aprovado aqui vira aprovação automática de trabalho não validado.
|
|
18
|
+
|
|
19
|
+
## O que caracteriza um achado GRAVE
|
|
20
|
+
|
|
21
|
+
- **Critério de aceite da spec sem cenário correspondente** — a lacuna faz a Feature ser aprovada sem aquele comportamento ter sido validado.
|
|
22
|
+
- **Cenário que passaria SEM a implementação** — ex.: "a página carrega", "o comando não dá erro" num fluxo que existia antes da Feature. É o mesmo vício já caçado no bug.md: um teste que não falharia não valida nada.
|
|
23
|
+
- **Resultado esperado não observável** — "verificar se funciona", "conferir se está correto", "validar o comportamento". Esperado sem critério objetivo torna o veredito arbitrário.
|
|
24
|
+
- **Cenário que testa implementação em vez de comportamento** — "a classe PedidoService existe", "a função retorna um array" — em vez do que o usuário/consumidor observa.
|
|
25
|
+
- **Cenário que contradiz a spec** — esperado que inverte uma regra de negócio explícita.
|
|
26
|
+
- **Cenário atribuído à Story errada** — o comportamento validado pertence a outra Story da decomposição (a reprova abriria o Bug no lugar errado).
|
|
27
|
+
|
|
28
|
+
## O que é MENOR
|
|
29
|
+
|
|
30
|
+
Pré-condições vagas mas completáveis, passos que poderiam ser mais concretos, ordem subótima, redundância parcial entre cenários.
|
|
31
|
+
|
|
32
|
+
<!-- requires-tools -->
|
|
33
|
+
## Como verificar
|
|
34
|
+
|
|
35
|
+
Você tem `Read`, `Glob` e `Grep`. Confira os passos contra o repositório real: a rota citada existe? O comando citado existe? Um plano cujos passos apontam para o que não existe produziria só `blocked` — e isso é um achado.
|
|
36
|
+
<!-- /requires-tools -->
|
|
37
|
+
|
|
38
|
+
## Barra de rigor
|
|
39
|
+
|
|
40
|
+
NÃO invente problemas. Um plano enxuto que cobre os critérios de aceite com esperados observáveis é um resultado legítimo e frequente — diga isso. O inverso também vale: "não consegui confirmar" não é aprovação.
|
|
41
|
+
|
|
42
|
+
## Consequência
|
|
43
|
+
|
|
44
|
+
Um achado **grave** aplica `spec-wave:critique-failed` e o plano NÃO é liberado (`spec-wave:qa-ready` não é aplicada): nenhuma execução de QA roda até a correção. Um achado **menor** é comentado e o plano segue. Reserve o grave para o que tornaria o verde automático enganoso.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: qa-plan
|
|
3
|
+
action: qa
|
|
4
|
+
description: Gera o plano de QA (qa-plan.md) de uma Feature a partir dos critérios de aceite da spec, com um ou mais cenários por Story.
|
|
5
|
+
tools: [Read, Glob, Grep]
|
|
6
|
+
maxTurns: 30
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Plano de QA de uma Feature
|
|
10
|
+
|
|
11
|
+
Você é um analista de QA experiente. A partir da Feature fornecida (spec.md, plan.md e a lista de Stories reais), escreva o **qa-plan.md**: os cenários de validação funcional que um executor vai rodar contra o checkout, um por critério de aceite relevante.
|
|
12
|
+
|
|
13
|
+
## Entrada
|
|
14
|
+
|
|
15
|
+
O payload JSON traz:
|
|
16
|
+
|
|
17
|
+
- `feature` — número e título da issue da Feature
|
|
18
|
+
- `stories` — as Stories REAIS (número da issue, título, corpo). **Todo cenário pertence a exatamente uma destas Stories, pelo número.**
|
|
19
|
+
- `spec` — o conteúdo de `spec.md` (critérios de aceite, fluxos, regras de negócio)
|
|
20
|
+
- `plan` — o conteúdo de `plan.md` (estratégia técnica — útil para saber COMO exercitar: endpoints, comandos, telas)
|
|
21
|
+
|
|
22
|
+
## Formato de saída (obrigatório)
|
|
23
|
+
|
|
24
|
+
Responda APENAS com o documento markdown, neste formato exato:
|
|
25
|
+
|
|
26
|
+
```markdown
|
|
27
|
+
# Plano de QA — [FEATURE] Título da Feature
|
|
28
|
+
<!-- spec-wave:qa-plan v1 issue=NUMERO_DA_FEATURE -->
|
|
29
|
+
|
|
30
|
+
## Cenário 1 — Story #412
|
|
31
|
+
|
|
32
|
+
**Critério:** AC-2 — cliente vê apenas os próprios pedidos
|
|
33
|
+
**Pré-condições:** dois usuários autenticáveis, cada um com ao menos um pedido
|
|
34
|
+
**Passos:**
|
|
35
|
+
1. Autenticar como usuário A
|
|
36
|
+
2. `GET /pedidos`
|
|
37
|
+
**Esperado:** resposta 200 contendo somente pedidos de A; nenhum pedido de B
|
|
38
|
+
|
|
39
|
+
## Cenário 2 — Story #412
|
|
40
|
+
...
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Regras do formato:
|
|
44
|
+
|
|
45
|
+
- O título de cada seção é `## Cenário N — Story #X`, onde `#X` é o número REAL de uma Story da lista `stories`. **Nunca invente números de issue.**
|
|
46
|
+
- `**Critério:**` e `**Esperado:**` são obrigatórios em todo cenário. `**Pré-condições:**` e `**Passos:**` são opcionais, mas quase sempre necessários.
|
|
47
|
+
- **Toda Story da lista precisa de ao menos um cenário** — uma Story sem cenário reprova o plano na validação determinística.
|
|
48
|
+
- Escreva em português (pt-BR).
|
|
49
|
+
|
|
50
|
+
## O que faz um cenário BOM
|
|
51
|
+
|
|
52
|
+
- **Deriva de um critério de aceite da spec** — cite-o no campo `**Critério:**` (ex.: "AC-3 — pedido cancelado não aparece na listagem"). Todo critério de aceite relevante da spec deve ter um cenário correspondente.
|
|
53
|
+
- **Resultado esperado OBSERVÁVEL**: um status HTTP, uma saída de comando, um registro no banco, um texto na tela. "Verificar se funciona" e "conferir se está correto" não são resultados — são a ausência de um.
|
|
54
|
+
- **Falharia sem a implementação**: um cenário que passaria num checkout sem a Feature não valida nada. Pense: "se ninguém tivesse implementado isso, este cenário quebraria?"
|
|
55
|
+
- **Testa COMPORTAMENTO, não implementação**: valide o que o usuário/consumidor observa, não a existência de uma classe ou o nome de uma função.
|
|
56
|
+
- **Executável por alguém sem contexto**: passos concretos (comandos, URLs, payloads), pré-condições explícitas (dados de teste, usuários, estado inicial).
|
|
57
|
+
|
|
58
|
+
<!-- requires-tools -->
|
|
59
|
+
## Exploração antes de escrever
|
|
60
|
+
|
|
61
|
+
Você tem `Read`, `Glob` e `Grep` no repositório. Use-os para ancorar os passos no que existe de verdade: os endpoints reais (rotas registradas), os comandos reais (scripts do package.json, Makefile), os seeds/fixtures disponíveis. Um passo `GET /api/pedidos` só vale se essa rota existe com esse nome. Não gaste mais do que o necessário: explore o suficiente para os passos serem executáveis, e então escreva o documento completo.
|
|
62
|
+
<!-- /requires-tools -->
|
|
63
|
+
|
|
64
|
+
## O que NÃO fazer
|
|
65
|
+
|
|
66
|
+
- Não inventar suíte de testes automatizada: o plano descreve validação funcional executável contra o checkout, não `describe/it`.
|
|
67
|
+
- Não cobrir requisitos não-funcionais genéricos (performance, segurança) a menos que a spec traga critério de aceite explícito e testável sobre eles.
|
|
68
|
+
- Não duplicar o mesmo critério em vários cenários — um cenário por comportamento distinto.
|
|
@@ -40,3 +40,16 @@ existing_services:
|
|
|
40
40
|
internal_libraries:
|
|
41
41
|
- "shared-logger"
|
|
42
42
|
- "db-client (TypeORM)"
|
|
43
|
+
|
|
44
|
+
# Decisões de modelagem de recursos COMPARTILHADOS entre features (opcional).
|
|
45
|
+
#
|
|
46
|
+
# `criada_por:` é obrigatório em cada entrada: a Feature que cria o recurso
|
|
47
|
+
# (ex.: "FT-01.7" ou "#42"), ou o literal SEM DONO enquanto ninguém o criar.
|
|
48
|
+
# "Não existe feature para editar esses valores" escrito em prosa fica meses
|
|
49
|
+
# sem ninguém agir; SEM DONO aparece no `spec-wave audit` como pendência de
|
|
50
|
+
# checklist antes de planejar a milestone.
|
|
51
|
+
#
|
|
52
|
+
# decisoes_de_modelagem:
|
|
53
|
+
# - recurso: "custo_canal"
|
|
54
|
+
# decisao: "Tabela própria; valores editados por ADMIN, consumidos por 4 features"
|
|
55
|
+
# criada_por: "SEM DONO"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: spec-wave
|
|
3
3
|
description: "Use when the user wants to set up a spec-driven GitHub workflow, create a Feature issue, generate spec.md or plan.md, decompose a Feature into Stories/Tasks, write RFC documentation, or audit and fix a Pull Request. Implements the RFC-001 workflow with GitHub Projects v2, labels, and AI-powered GitHub Actions."
|
|
4
|
-
argument-hint: "[info|setup|update|doctor|issue|feature|spec|plan|ready|decompose|order|implement|task|story|move|uninstall|rfc|bug|triage|fix-pr] [target]"
|
|
4
|
+
argument-hint: "[info|setup|update|doctor|preflight|audit|issue|feature|spec|plan|ready|decompose|order|implement|merge|qa|task|story|move|uninstall|rfc|bug|triage|fix-pr] [target]"
|
|
5
5
|
user-invocable: true
|
|
6
6
|
allowed-tools:
|
|
7
7
|
- Bash(npx @spec-wave/cli@latest *)
|
|
@@ -77,7 +77,7 @@ npx @spec-wave/cli@latest mode # estado atual dos dois lados do
|
|
|
77
77
|
npx @spec-wave/cli@latest mode local # desarma os workflows
|
|
78
78
|
npx @spec-wave/cli@latest run <issue> --dry-run # explica o próximo passo sem executar
|
|
79
79
|
npx @spec-wave/cli@latest run <issue> # executa
|
|
80
|
-
npx @spec-wave/cli@latest run --pr <n> # code-review (+ qa, se
|
|
80
|
+
npx @spec-wave/cli@latest run --pr <n> # code-review (+ qa, se aprovado OU mergeado)
|
|
81
81
|
```
|
|
82
82
|
|
|
83
83
|
O `run` decide o passo pelo estado da issue (documentos existentes + labels), respeita os portões humanos (`needs-human`, `critique-failed`), recusa rodar com uma label de gatilho pendente e **exige `--apply`** para o `decompose-apply`, que cria issues. Sempre mostre o `--dry-run` ao usuário antes de executar.
|
|
@@ -126,6 +126,7 @@ Labels de gatilho:
|
|
|
126
126
|
- `spec-wave:decompose` → dispara `decompose.yml` → gera (ou **re-critica**) o **rascunho** em `decomposition.md`. **Não cria issue nenhuma.**
|
|
127
127
|
- `spec-wave:decompose-apply` → dispara o mesmo workflow em modo aplicação → cria as Stories e Tasks **a partir do rascunho revisado**
|
|
128
128
|
- `spec-wave:bug` → dispara `generate-bug.yml` → gera `docs/bugs/<slug>/bug.md` (só para issues `[BUG]`)
|
|
129
|
+
- `spec-wave:qa` → dispara `generate-qa-plan.yml` → gera (ou **re-critica COMO ESTÁ**) o plano de QA em `docs/features/<slug>/qa-plan.md`. **Só em Feature** (o plano é por Feature; numa Story o Action aponta a Feature-pai). A **execução** é sempre local: `npx @spec-wave/cli@latest qa <issue>`.
|
|
129
130
|
|
|
130
131
|
Labels de **estado** (gravadas pelas automações — **não** são gatilhos, não as adicione por conta própria):
|
|
131
132
|
- `spec-wave:decompose-ready` → o rascunho da decomposição passou pela crítica e espera **revisão humana**; aplique `spec-wave:decompose-apply` para criar as issues
|
|
@@ -133,12 +134,16 @@ Labels de **estado** (gravadas pelas automações — **não** são gatilhos, n
|
|
|
133
134
|
- `spec-wave:needs-human` → a crítica reprovou N vezes seguidas (default 3); **para o fluxo** até uma pessoa revisar e remover a label
|
|
134
135
|
- `spec-wave:decomposed` → a Feature/RFC já foi decomposta; o `decompose` pula silenciosamente enquanto ela existir (veja *Guard de idempotência* abaixo)
|
|
135
136
|
- `spec-wave:bug-approved` → o `bug.md` passou na validação das seis seções obrigatórias
|
|
137
|
+
- `spec-wave:qa-ready` → o `qa-plan.md` passou na validação + crítica e espera **revisão humana** — é o pré-requisito de `qa <issue>` (o veredito verde avança a Etapa sozinho, então o portão humano é a revisão do plano). ⚠️ Não confunda com `spec-wave:ready` (gatilho da validação de spec/plan).
|
|
138
|
+
- `spec-wave:qa-approved` → a execução do QA passou. Aplicada na Story (e na Feature, quando todas as Stories passarem).
|
|
136
139
|
|
|
137
140
|
Label **modificadora** (esta você pode aplicar):
|
|
138
141
|
- `spec-wave:model:<apelido>` → força um modelo específico **naquela execução**, resolvido por `ai.modelAliases` no `.spec-wave.json`. Serve para reprocessar um caso difícil num modelo mais forte sem editar a configuração do repositório inteiro. Duas dessas labels na mesma issue = ambíguo, nenhuma vale.
|
|
139
142
|
|
|
140
143
|
A etapa **🚧 Desenvolvimento** é coberta pelo comando **local** `npx @spec-wave/cli@latest implement <número>` (não é uma label/Action): lê uma **Feature** (todas as Stories pendentes, em ordem de dependência), uma Story ou uma Task e aciona o spec-kit para implementar. Veja `/spec-wave implement`.
|
|
141
144
|
|
|
145
|
+
A etapa **🧪 QA** tem artefato e comando próprios: a label `spec-wave:qa` gera o `qa-plan.md` (validado + criticado → `spec-wave:qa-ready`), e a **execução é sempre local** — `npx @spec-wave/cli@latest qa <issue>` roda os cenários contra o checkout. Verde: `qa-approved` + Story → 📋 Homologação (Bug → 🚀 Deploy, sem Homologação). Vermelho: **um Bug por cenário reprovado**, já com `bug.md` commitado. Inconclusivo (`blocked` sem `fail`): nada move, nenhum Bug. Veja `/spec-wave qa`.
|
|
146
|
+
|
|
142
147
|
---
|
|
143
148
|
|
|
144
149
|
## Referência da CLI (conheça os parâmetros ANTES de executar)
|
|
@@ -253,7 +258,44 @@ Sem flags. Roda um checklist de diagnóstico no repositório atual: token GitHub
|
|
|
253
258
|
|----------|------|-----------|
|
|
254
259
|
| `<feature>` | string (obrigatório) | Número da issue da **Feature**, ex.: `12` ou `#12`. Argumento posicional. |
|
|
255
260
|
|
|
256
|
-
> **Sem argumento**, monta o mapa de TODAS as Features abertas fora de 🎉 Done num grafo só (conjunto vindo do board), com a Feature de cada Story ao lado — nesse escopo a dependência entre Features entra na ordenação. Com `<feature>`, lista as Stories da Feature em **ordem topológica** pelas dependências (linha `Depende de: #N` no corpo + relação nativa *blocked by*, mescladas), com a Etapa atual de cada uma no board. Dependências para **fora da Feature** não entram na ordenação (não há como saber onde a Story de outra Feature entra nesta sequência), mas aparecem em **"Bloqueadas por fora desta Feature"**, com o estado de cada bloqueadora. Avisa sobre **ciclos de dependência** (essas Stories ficam fora da ordem — corrija as linhas `Depende de`)
|
|
261
|
+
> **Sem argumento**, monta o mapa de TODAS as Features abertas fora de 🎉 Done num grafo só (conjunto vindo do board), com a Feature de cada Story ao lado — nesse escopo a dependência entre Features entra na ordenação. Com `<feature>`, lista as Stories da Feature em **ordem topológica** pelas dependências (linha `Depende de: #N` no corpo + relação nativa *blocked by*, mescladas), com a Etapa atual de cada uma no board. Dependências para **fora da Feature** não entram na ordenação (não há como saber onde a Story de outra Feature entra nesta sequência), mas aparecem em **"Bloqueadas por fora desta Feature"**, com o estado de cada bloqueadora. Avisa sobre **ciclos de dependência** (essas Stories ficam fora da ordem — corrija as linhas `Depende de`), sobre **dependências fora de ordem** (Story já em Desenvolvimento+ dependendo de outra que não está Done) e sobre **milestone divergente** (Story sem milestone ou em milestone diferente do da Feature — órfã de toda visão de release; sem milestone na Feature, nada é comparado). Use antes de escolher qual Story implementar, e logo após o `decompose --apply` como detector do pós-apply.
|
|
262
|
+
|
|
263
|
+
### `@spec-wave/cli preflight --milestone <nome>` — confere tudo ANTES de gerar as specs (comando LOCAL)
|
|
264
|
+
| Flag/Arg | Tipo | Descrição |
|
|
265
|
+
|----------|------|-----------|
|
|
266
|
+
| `--milestone <nome>` | string (obrigatório) | Título da milestone a inventariar. |
|
|
267
|
+
| `--json` | boolean | O relatório em JSON, para ramificar. |
|
|
268
|
+
|
|
269
|
+
> Um comando reporta: token utilizável, modo de execução (config × variável do repositório), publicação por PR, e as Features da milestone com o **estado do `spec.md` de cada uma** (na base, no disco, em PR aberto, em branch sem PR, a gerar). Existe porque **cada geração paga um modelo**: um erro de configuração descoberto na sétima Feature custa sete gerações — e regenerar um documento que já vive num PR descarta a revisão em curso. Sai com código 1 quando há bloqueio. Rode SEMPRE antes de uma rodada de specs por milestone.
|
|
270
|
+
|
|
271
|
+
### `@spec-wave/cli audit --milestone <nome>` — cruza as specs da milestone como CONJUNTO (comando LOCAL)
|
|
272
|
+
| Flag/Arg | Tipo | Descrição |
|
|
273
|
+
|----------|------|-----------|
|
|
274
|
+
| `--milestone <nome>` | string (obrigatório) | Título da milestone a auditar. |
|
|
275
|
+
| `--critique` | boolean | Roda também a **crítica adversarial de conjunto** — UMA chamada de modelo sobre todas as specs juntas, procurando contradição ENTRE documentos. |
|
|
276
|
+
| `--json` | boolean | O relatório em JSON (com `critica.markdown` pronto para comentar nas issues). |
|
|
277
|
+
|
|
278
|
+
> A crítica normal audita cada documento contra os insumos da **mesma** Feature; este comando olha o que só existe **no par**: dependência circular entre Features, bloqueante em milestone **posterior** à de quem depende dela, referência a issue inexistente (materiais — exit 1), dependência que nenhuma Feature cria ("recurso sem dono"), sobreposição do slug com código existente e decisão de modelagem com `criada_por: SEM DONO` no `tech_context.yml` (avisos heurísticos — **confira antes de reportar**). Rode depois que as specs existirem (PR aberto também conta), antes de gerar os planos. Achado material é decisão de PO: comente nas issues **dos dois lados**.
|
|
279
|
+
|
|
280
|
+
### `@spec-wave/cli merge <feature>` — mergeia os PRs empilhados das Stories (comando LOCAL)
|
|
281
|
+
| Flag/Arg | Tipo | Descrição |
|
|
282
|
+
|----------|------|-----------|
|
|
283
|
+
| `<feature>` | string (obrigatório) | Número da issue da **Feature**, ex.: `12` ou `#12`. |
|
|
284
|
+
| `--yes` | boolean | Executa os merges. **Sem ela, só mostra o plano** (fila na ordem, retargets, avisos). |
|
|
285
|
+
| `--keep-branches` | boolean | Não apaga as branches das Stories após o merge. |
|
|
286
|
+
|
|
287
|
+
> O `implement` empilha os PRs (cada um baseado no anterior) e o merge da pilha é **ordem-dependente**: `--delete-branch` no primeiro PR fecha o segundo. Este comando encapsula a sequência segura — para cada PR na ordem topológica das Stories: reaponta a base para a default, mergeia com **merge commit**, atualiza o board (**merge move até 🧪 QA**) e **só no fim** apaga as branches. **PR em rascunho bloqueia o plano inteiro** (marcar pronto é a revisão humana — o comando não pula isso). Rodar de novo **retoma**: PR mergeado sai do plano. Use após a revisão, em vez de mergear à mão com `gh`.
|
|
288
|
+
|
|
289
|
+
### `@spec-wave/cli qa <issue>` — executa o plano de QA localmente (e `qa --pr-number <n>` no Action)
|
|
290
|
+
| Flag/Arg | Tipo | Descrição |
|
|
291
|
+
|----------|------|-----------|
|
|
292
|
+
| `<issue>` | string | Número da **Feature** (todos os cenários das Stories ainda sem `qa-approved`), **Story** (os cenários dela) ou **Bug** (a seção `Teste de Regressão` do `bug.md`). |
|
|
293
|
+
| `--only <n[,m]>` | string | Só o(s) cenário(s) indicado(s) — número **posicional** no plano. O restante herda o veredito do último relatório. |
|
|
294
|
+
| `--severity <p>` | string | Severidade dos Bugs abertos na reprova: `P0`–`P3` (default: `qa.defaultBugPriority` ou `P2`). |
|
|
295
|
+
| `--dry-run` | boolean | Monta o contexto e imprime cenários + comando. **Zero escrita no GitHub.** |
|
|
296
|
+
| `--pr-number <n>` | string | Modo Action (mutuamente exclusivo com `<issue>`): move a Feature/Bug do PR aprovado/mergeado para 🧪 QA. |
|
|
297
|
+
|
|
298
|
+
> **Pré-requisitos:** Feature dona do plano com `spec-wave:qa-ready` (portão humano — D-QA4), item já em 🧪 QA (o comando **não promove**; Etapa posterior = informa e sai 0), executor em `qa.command` no `.spec-wave.json` (ou `SPEC_WAVE_QA_CMD`) — sem ele, só monta o contexto. **Sempre `--dry-run` primeiro.** Desfechos: verde → `qa-approved` + Story para 📋 Homologação (Bug → 🚀 Deploy; Feature quando TODAS as Stories liberarem; **Bug filho aberto segura a Story mesmo verde**); vermelho → 1 Bug por cenário reprovado (filho da Story, ✅ Ready, `bug.md` determinístico commitado — exceção documentada à regra do `spec-wave:bug`), exit 1; `blocked` sem `fail` → inconclusivo: nada move, nenhum Bug, exit 1. Re-teste após o fix: `qa <story> --only <cenário>` (não duplica Bug — comenta no existente).
|
|
257
299
|
|
|
258
300
|
### `@spec-wave/cli task <start|done> <n>` — transições de Task no board (comando LOCAL)
|
|
259
301
|
| Flag/Arg | Tipo | Descrição |
|
|
@@ -692,7 +734,7 @@ Aciona o spec-kit para implementar uma **Feature** (todas as Stories pendentes,
|
|
|
692
734
|
- Se o spec-kit **não** estiver configurado, o comando só monta o contexto e mostra como configurar (`specKit.command` / `SPEC_WAVE_IMPLEMENT_CMD`). Ajude o usuário a definir o template (placeholders: `{tasksFile} {specFile} {planFile} {issue} {type} {title}`).
|
|
693
735
|
- Use `--feature-dir docs/features/<slug>` se a resolução automática da Feature falhar (a skill avisa com warning) e você quiser anexar `spec.md`/`plan.md` como contexto.
|
|
694
736
|
6. **No modo Feature**, siga o contexto Story a Story, na ordem listada: para cada Story pendente, implemente as Tasks com `task start`/`task done`, depois commit + PR + `npx @spec-wave/cli@latest story review <n>`; só então passe à próxima Story. **Bug** tem modo próprio (RFC-004): sem tasks e sem spec/plan, com quatro fases — reproduzir → causa raiz → fix mínimo → teste de regressão — e o `bug.md` entrando como hipótese a confirmar. Se a issue não for Feature, Story, Task nem Bug (ex.: Spike, Epic), o comando recusa. Feature **sem Stories** → rode `/spec-wave decompose` primeiro. **Ciclo de dependências** → corrija as linhas `Depende de:` (veja `spec-wave order`).
|
|
695
|
-
7. Ao final (Tasks em **🎉 Done**, Story em **👀 Code Review**; a Feature só vai para Code Review quando a última Story concluir — no modo Feature, isso acontece dentro da mesma execução): confirme o resultado com o usuário e oriente a revisão dos PRs.
|
|
737
|
+
7. Ao final (Tasks em **🎉 Done**, Story em **👀 Code Review**; a Feature só vai para Code Review quando a última Story concluir — no modo Feature, isso acontece dentro da mesma execução): confirme o resultado com o usuário e oriente a revisão dos PRs. **Avise que os PRs estão empilhados** e que o merge é ordem-dependente: depois da revisão (PRs marcados prontos), o caminho é `npx @spec-wave/cli@latest merge <feature>` — nunca `gh pr merge --delete-branch` à mão em PR de pilha.
|
|
696
738
|
|
|
697
739
|
---
|
|
698
740
|
|
|
@@ -767,6 +809,33 @@ Para criar um Bug: `npx @spec-wave/cli@latest bug --title "..." [--parent <n>] [
|
|
|
767
809
|
|
|
768
810
|
---
|
|
769
811
|
|
|
812
|
+
### `/spec-wave qa <número-da-issue>`
|
|
813
|
+
|
|
814
|
+
A etapa **🧪 QA**: plano por Feature + execução local com veredito. Duas metades, nesta ordem obrigatória:
|
|
815
|
+
|
|
816
|
+
**1. Gerar/criticar o plano (Feature):**
|
|
817
|
+
```bash
|
|
818
|
+
gh issue edit <feature> --add-label "spec-wave:qa"
|
|
819
|
+
```
|
|
820
|
+
- Arquivo ausente → gera `docs/features/<slug>/qa-plan.md` via IA (publicado em PR). Arquivo presente → valida + critica **COMO ESTÁ** (edições manuais preservadas). Regerar do zero = apagar o arquivo e reaplicar.
|
|
821
|
+
- Requer `spec.md` + `plan.md` na base. Limpo → `spec-wave:qa-ready`; grave → `critique-failed`.
|
|
822
|
+
- **Só em Feature** — numa Story o Action comenta apontando a Feature-pai; Bug usa o `Teste de Regressão` do `bug.md`.
|
|
823
|
+
|
|
824
|
+
**2. Revisar o plano e executar (sempre local, SEMPRE `--dry-run` primeiro):**
|
|
825
|
+
```bash
|
|
826
|
+
npx @spec-wave/cli@latest qa <issue> --dry-run # cenários-alvo + comando; zero escrita no GitHub
|
|
827
|
+
npx @spec-wave/cli@latest qa <issue> # executa e dá o veredito
|
|
828
|
+
```
|
|
829
|
+
- A revisão do plano é o **portão humano** (D-QA4): sem `qa-ready` na Feature o comando recusa — porque o verde avança a Etapa **sozinho** (D-QA3).
|
|
830
|
+
- Regras de edição do plano: seções `## Cenário N — Story #X` (posição manda, não o número escrito), `**Critério:**`/`**Esperado:**` obrigatórios.
|
|
831
|
+
- Desfechos: **verde** → `qa-approved`, Story → 📋 Homologação, Bug → 🚀 Deploy (D-QA6), Feature quando TODAS as Stories liberarem; Bug filho aberto **segura** a Story mesmo verde. **Vermelho** → 1 Bug por cenário reprovado (filho da Story, ✅ Ready, milestone herdado) com `bug.md` **determinístico commitado pelo comando e `bug-approved` aplicada** — exceção explícita à Regra fundamental: reprodução, esperado/obtido e regressão são a execução observada, e regenerar por IA só alucina; **não** aplique `spec-wave:bug` nesses Bugs. **Inconclusivo** (`blocked` sem `fail`) → nada move, nenhum Bug, exit 1.
|
|
832
|
+
- Re-teste após o fix: `npx @spec-wave/cli@latest qa <story> --only <cenário>` — não duplica Bug (comenta no existente).
|
|
833
|
+
- **PROIBIDO corrigir código durante a execução** — QA não conserta; alterar o código invalida o veredito.
|
|
834
|
+
|
|
835
|
+
Sem `qa.command` no `.spec-wave.json` (nem `SPEC_WAVE_QA_CMD`), o comando monta o contexto em `.spec-wave/qa-<n>.md` e orienta — configure como no `specKit.command` do implement.
|
|
836
|
+
|
|
837
|
+
---
|
|
838
|
+
|
|
770
839
|
### `/spec-wave fix-pr <número-do-pr>`
|
|
771
840
|
|
|
772
841
|
Audita um Pull Request e corrige automaticamente os problemas encontrados — segurança, arquitetura, infraestrutura e qualidade de código. Cada fix vira um commit separado no branch do PR. Cada review comment recebe uma resposta com o hash do commit.
|
|
@@ -884,6 +953,10 @@ docs/
|
|
|
884
953
|
decomposition.md ← rascunho gerado quando spec-wave:decompose é adicionado (3º).
|
|
885
954
|
REVISÁVEL e EDITÁVEL à mão; as issues só nascem com
|
|
886
955
|
spec-wave:decompose-apply
|
|
956
|
+
qa-plan.md ← plano de QA gerado quando spec-wave:qa é adicionado (4º,
|
|
957
|
+
com a Feature já em 🧪 QA). Um cenário por critério de
|
|
958
|
+
aceite, seções "## Cenário N — Story #X"; executado
|
|
959
|
+
localmente por `spec-wave qa <issue>`
|
|
887
960
|
rfcs/
|
|
888
961
|
<slug-do-rfc>/
|
|
889
962
|
decomposition.md ← mesmo papel, com "## Task N" (RFC não usa spec/plan)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
name: Generate QA Plan
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
issues:
|
|
5
|
+
types: [labeled]
|
|
6
|
+
|
|
7
|
+
# Mesmo desenho do decompose.yml: `labeled` dispara para QUALQUER label, então o
|
|
8
|
+
# run que não vai fazer nada ganha um grupo único (`spec-wave-noop-<run_id>`) e
|
|
9
|
+
# não disputa a fila — com `cancel-in-progress: false`, um run inútil na fila
|
|
10
|
+
# cancelaria o que estava PENDENTE (ver o comentário longo no decompose.yml).
|
|
11
|
+
#
|
|
12
|
+
# O namespace `spec-wave-item-<issue>` é COMPARTILHADO com decompose.yml,
|
|
13
|
+
# generate-spec/plan/bug e o job `move` do code-review.yml: este workflow também
|
|
14
|
+
# publica documento em branch própria + Pull Request, e lê spec.md/plan.md que
|
|
15
|
+
# uma geração concorrente estaria trocando.
|
|
16
|
+
concurrency:
|
|
17
|
+
group: >-
|
|
18
|
+
${{ github.event.label.name == 'spec-wave:qa'
|
|
19
|
+
&& format('spec-wave-item-{0}', github.event.issue.number)
|
|
20
|
+
|| format('spec-wave-noop-{0}', github.run_id) }}
|
|
21
|
+
cancel-in-progress: false
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
generate-qa-plan:
|
|
25
|
+
# `spec-wave:qa` numa Feature gera (ou re-critica) o qa-plan.md. O comando
|
|
26
|
+
# trata sozinho os outros tipos (Story → aponta a Feature-pai; Bug → usa o
|
|
27
|
+
# Teste de Regressão do bug.md), então o filtro de título fica amplo de
|
|
28
|
+
# propósito — o `if:` só corta o ruído de labels sem relação.
|
|
29
|
+
# Modo de execução: `spec-wave mode local` cria a variável de repositório
|
|
30
|
+
# SPEC_WAVE_EXECUTION=local e este job passa a ser PULADO.
|
|
31
|
+
if: >
|
|
32
|
+
vars.SPEC_WAVE_EXECUTION != 'local' &&
|
|
33
|
+
github.event.label.name == 'spec-wave:qa'
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
permissions:
|
|
36
|
+
issues: write
|
|
37
|
+
# O commit do qa-plan.md vai por Git Data API (contents: write) para uma
|
|
38
|
+
# branch própria (`spec-wave/<n>-qa-plan`), nunca a default; sem
|
|
39
|
+
# `pull-requests: write` o commit existe e o PR não.
|
|
40
|
+
contents: write
|
|
41
|
+
pull-requests: write
|
|
42
|
+
|
|
43
|
+
steps:
|
|
44
|
+
- uses: actions/checkout@v4
|
|
45
|
+
with:
|
|
46
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
47
|
+
|
|
48
|
+
- uses: actions/setup-node@v4
|
|
49
|
+
with:
|
|
50
|
+
node-version: '24'
|
|
51
|
+
|
|
52
|
+
- name: Instala a CLI
|
|
53
|
+
run: npm install -g @spec-wave/cli@{{CLI_VERSION}}
|
|
54
|
+
|
|
55
|
+
- name: Generate QA plan
|
|
56
|
+
run: spec-wave generate-qa-plan --issue-number ${{ github.event.issue.number }}
|
|
57
|
+
env:
|
|
58
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
59
|
+
GH_PR_TOKEN: ${{ secrets.GH_PR_TOKEN }}
|
|
60
|
+
PROJECT_TOKEN: ${{ secrets.GH_PROJECT_TOKEN }}
|
|
61
|
+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
62
|
+
CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
63
|
+
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
|
|
64
|
+
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
name: QA
|
|
2
2
|
|
|
3
|
+
# Dois gatilhos, um destino: aprovação formal OU merge movem a Feature para
|
|
4
|
+
# 🧪 QA. O de merge existe porque o autor não consegue aprovar o próprio PR —
|
|
5
|
+
# num fluxo solo, QA por aprovação nunca aconteceria — e porque homologação de
|
|
6
|
+
# verdade começa com o código integrado. Espelha o `run --pr` do modo local.
|
|
3
7
|
on:
|
|
4
8
|
pull_request_review:
|
|
5
9
|
types: [submitted]
|
|
10
|
+
pull_request:
|
|
11
|
+
types: [closed]
|
|
6
12
|
|
|
7
13
|
concurrency:
|
|
8
14
|
group: spec-wave-qa-${{ github.event.pull_request.number }}
|
|
@@ -25,10 +31,12 @@ jobs:
|
|
|
25
31
|
# Aqui a guarda é INDISPENSÁVEL, não defensiva: `pull_request_review`
|
|
26
32
|
# dispara por uma aprovação HUMANA, independentemente de quem abriu o
|
|
27
33
|
# PR. Aprovar o PR da spec moveria a Feature para 🧪 QA.
|
|
34
|
+
# A última linha aceita os dois eventos: review aprovada (pull_request_review)
|
|
35
|
+
# ou PR fechado COM merge (pull_request closed — fechado sem merge não conta).
|
|
28
36
|
if: >
|
|
29
37
|
vars.SPEC_WAVE_EXECUTION != 'local' &&
|
|
30
38
|
!startsWith(github.event.pull_request.head.ref, 'spec-wave/') &&
|
|
31
|
-
github.event.review.state == 'approved'
|
|
39
|
+
(github.event.review.state == 'approved' || github.event.pull_request.merged == true)
|
|
32
40
|
runs-on: ubuntu-latest
|
|
33
41
|
permissions:
|
|
34
42
|
issues: write
|