feat: work-issue skill
This commit is contained in:
parent
1c1a379897
commit
111308f00e
3 changed files with 120 additions and 1 deletions
81
.cursor/skills/work-issue/SKILL.md
Normal file
81
.cursor/skills/work-issue/SKILL.md
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
---
|
||||
name: work-issue
|
||||
description: Conduz uma GitHub Issue rastreável do Teqo do claim ao merge em stage — claim (pnpm agent:claim), verificação do modelo declarado na Issue, freshness audit do plano, execução das fases (schema/server → UI via /impeccable → gates), /simplify + capture-review-debts, PR --base stage com Closes #N, acompanhamento do CI até o merge. Usar quando o usuário pedir para implementar/trabalhar uma Issue ("trabalha a issue #N", "implementa o B79", "pega a próxima issue", "vamos fazer o X", "continua a implementação").
|
||||
---
|
||||
|
||||
# Trabalhar uma Issue (claim → merge em stage)
|
||||
|
||||
Esta skill conduz UMA Issue rastreável do claim ao merge em `stage`. Substitui o antigo fluxo implement-roadmap-item + close-delivery + ship-to-main. **GitHub Issues são a fonte canônica** de spec/status/deps/prio/modelo; `docs/roadmap.md` é legado congelado e nunca é editado aqui (registro de entrega vai na Issue + `docs/plans/<slug>.md` + notebook do projeto).
|
||||
|
||||
**Proibido neste fluxo:** `pnpm agent:promote` (promote stage→main é humano), qualquer acesso a DB de stage/prod, merge sem CI green, editar outras Issues `in-progress`.
|
||||
|
||||
**Qualidade de decisão e dados:** aplique [decision-quality.md](../plan-issue/decision-quality.md) ao auditar e fatiar (caro vs barato, Opções+Recomendação+rejeitadas, appetite, rabbit holes, tracer bullet cedo) e [data-presentation.md](../plan-issue/data-presentation.md) ao auditar/fatiar superfícies com KPI/mapa/série/ranking.
|
||||
|
||||
## Checklist do fluxo
|
||||
|
||||
```
|
||||
- [ ] 1. Claim: pnpm agent:claim (ou -- --issue <N>) — o brief do stdout é o contrato
|
||||
- [ ] 2. Verificação de modelo (best effort): comparar model: da Issue com o modelo da sessão
|
||||
- [ ] 3. Freshness audit (enxuto) do plano contra o repositório
|
||||
- [ ] 4. Executar as fases (schema/server → UI via /impeccable → gates de engenharia)
|
||||
- [ ] 5. /simplify no diff da sessão → capture-review-debts
|
||||
- [ ] 6. Fechar em stage: fast gate → branch → commit → gh pr create --base stage (Closes #N)
|
||||
→ gh pr merge --auto --merge → gh pr checks --watch até o merge → consolidar pontas soltas
|
||||
```
|
||||
|
||||
## Passo 1 — Claim
|
||||
|
||||
```bash
|
||||
pnpm agent:claim # pega o topo da fila (ready, desbloqueadas, por prio)
|
||||
pnpm agent:claim -- --issue <N> # quando o usuário especifica
|
||||
```
|
||||
|
||||
O brief impresso no stdout é o contrato: id, priority, **model**, spec, link do plano. O claim faz o swap de label `ready → in-progress` com lock otimista. Se falhar ("claimed by someone else"), re-rodar — nunca forçar.
|
||||
|
||||
## Passo 2 — Verificação de modelo (best effort, não programática)
|
||||
|
||||
Leia a propriedade `model:` do brief e compare com o modelo da sessão atual pela tabela de capacidade de `model-selection`. Regra **assimétrica** (decisão travada 2026-07-30):
|
||||
|
||||
- Sessão **mais fraca** que o especificado → assume-se escolha consciente do humano: **informa em uma linha e continua, sem pausar**.
|
||||
- Sessão **mais forte** que o especificado → possível erro do humano: **informa e pausa** ("a Issue pede X, você está em Y — seguir mesmo assim?").
|
||||
- Propriedade **ausente** → aplique `model-selection` uma vez e registre a escolha na Issue (`gh issue edit <N>` no body, frontmatter `model:`).
|
||||
|
||||
Subagentes despachados via `Task` saem **no modelo da propriedade** quando couber (`Task.model`).
|
||||
|
||||
## Passo 3 — Freshness audit (enxuto)
|
||||
|
||||
O plano foi escrito no passado e o repositório andou. Cheque, afirmação por afirmação:
|
||||
|
||||
- Arquivos citados no plano existem? Utilities "a reusar" têm a assinatura que o plano assume?
|
||||
- Premissas de schema batem com `src/payload-types.ts` e `src/migrations/`?
|
||||
- Deps do frontmatter estão `done`/`in-prod` (ou fechadas)? Dependência dura não entregue → pare e proponha (fazer a dep primeiro ou corte explícito).
|
||||
- Questões em aberto já respondidas pelo código/notebook?
|
||||
|
||||
Desfechos: **divergência factual** (caminho renomeado, assinatura) → corrija o plano na mesma sessão e siga; **divergência material de produto** → pare e pergunte. Não reescreva o plano inteiro: freshness audit é enxuto, não uma re-planificação.
|
||||
|
||||
## Passo 4 — Executar as fases
|
||||
|
||||
Ordem fixa, fases pequenas e verificáveis, respeitando o appetite do plano:
|
||||
|
||||
1. **Schema e server** — migrations (`pnpm migrate:create`, seguir `payload-migrations`), collections, utilities, server actions, testes de domínio. Guardrails do repo: Local API com `user` → `overrideAccess: false`; escrita multi-collection → transação com `req: { transactionID }`; pessoa → join com `Contact`; opt-in/PII → `Consent` por chave estável falhando fechado.
|
||||
2. **UI via /impeccable** (classes B/C/D — a classe está no plano; se A, declare "Impeccable: N/A" e siga só engenharia): shape conforme a classe → craft → critique → (harden/optimize **só sob gatilho**) → polish. Paleta = tokens `data-theme='campaign'`; reusar `src/components/ui` e shells existentes; shape obrigatório em C **para** para confirmação do brief antes do craft.
|
||||
3. **Gates de engenharia** — fast gate local: `pnpm lint`, `pnpm exec tsc --noEmit`, `pnpm test:unit`, `pnpm format:check`, `pnpm check:cycles` (+ `pnpm migrate && pnpm db:seed:minimal && pnpm test:int` se tocou schema). Scan Aikido dos arquivos editados. Comandos bare, nunca piped.
|
||||
|
||||
Tracer bullet: se a Issue for grande, a primeira fatia vertical real (schema mínimo → uma action → uma superfície UI) vem cedo.
|
||||
|
||||
## Passo 5 — /simplify + débitos
|
||||
|
||||
Rode `/simplify` sobre o diff da sessão. Follow-ups maiores que o cleanup → `capture-review-debts` (registra via `agent:register`/`agent:file-miss`; **nunca** edita Issue `in-progress` — nem esta; débito do mesmo pai vira Issue nova com `depends: [<id-do-pai>]`).
|
||||
|
||||
## Passo 6 — Fechar em stage
|
||||
|
||||
1. Fast gate verde (Passo 4.3).
|
||||
2. Branch `agent/<id>-<slug>` (worktrees do Cursor são donos da criação; commits lógicos).
|
||||
3. `gh pr create --base stage` com `Closes #<N>` no body.
|
||||
4. `gh pr merge --auto --merge <PR>`.
|
||||
5. **Acompanhe os checks até o merge** (`gh pr checks <PR> --watch`): falha no ci-pr → corrige na mesma branch e reempurra (o auto-merge dispara de novo quando verde).
|
||||
6. O flip `in-progress → done` é **determinístico no CI** (workflow `issue-done-on-stage-merge.yml` lê o `Closes #N` no merge em stage). O agente espera o merge apenas para verificar e **consolidar pontas soltas**: débitos não registrados, doc da sessão pendente (notebook do projeto + `docs/plans/<slug>.md` com Status/Atualizado em), comentário de fechamento na Issue com o que entrou. Se o agente falhar depois do merge, o status já está correto.
|
||||
|
||||
## Resumo final ao usuário
|
||||
|
||||
Issue trabalhada + verificação de modelo (declarado vs sessão, ou registro do ausente), veredito do freshness audit, o que entrou por fase, resultado do critique/polish (se UI), simplify + débitos registrados, gates, link do PR e estado do merge em stage, pontas soltas consolidadas. Nunca anuncie promote — `in-prod` é humano (`pnpm agent:promote --i-am-human`).
|
||||
28
.github/workflows/issue-done-on-stage-merge.yml
vendored
Normal file
28
.github/workflows/issue-done-on-stage-merge.yml
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
name: Stage merge flips claimed issues to done
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [closed]
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: read
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
issue-done:
|
||||
if: github.event.pull_request.base.ref == 'stage' && github.event.pull_request.merged == true
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
steps:
|
||||
- name: Flip Closes/Fixes #N issues from in-progress to done
|
||||
run: |
|
||||
body="$(gh pr view "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" --json body --jq .body)"
|
||||
numbers="$(printf '%s' "$body" | grep -oiE '(closes|fixes) #[0-9]+' | grep -oE '[0-9]+' | sort -u)"
|
||||
for n in $numbers; do
|
||||
gh issue edit "$n" --repo "$GITHUB_REPOSITORY" --remove-label in-progress --add-label done || true
|
||||
gh issue comment "$n" --repo "$GITHUB_REPOSITORY" \
|
||||
--body "Merged em stage via PR #${PR_NUMBER} — done; \`in-prod\` entra no promote humano." || true
|
||||
done
|
||||
|
|
@ -79,7 +79,8 @@ const queue = openReady
|
|||
if (flags['dry-run'] || flags['dryrun']) {
|
||||
console.log(`[agent:claim] ${queue.length} unblocked ready issue(s):`)
|
||||
for (const entry of queue) {
|
||||
console.log(` #${entry.issue.number} [${entry.priority}] ${entry.issue.title}`)
|
||||
const model = entry.meta.model ? ` model:${entry.meta.model}` : ''
|
||||
console.log(` #${entry.issue.number} [${entry.priority}]${model} ${entry.issue.title}`)
|
||||
}
|
||||
process.exit(0)
|
||||
}
|
||||
|
|
@ -119,6 +120,15 @@ gh([
|
|||
const { rest } = parseFrontmatter(pick.issue.body)
|
||||
console.log(`\n[agent:claim] Claimed #${pick.issue.number} — ${pick.issue.title}`)
|
||||
console.log(` id: ${pick.meta.id ?? '(none)'} priority: ${pick.priority}`)
|
||||
if (pick.meta.model) {
|
||||
console.log(
|
||||
` model: ${pick.meta.model} (propriedade da Issue — verificar, não recalcular; ver skill model-selection)`,
|
||||
)
|
||||
} else {
|
||||
console.log(
|
||||
' model: ausente — aplicar model-selection uma vez e registrar na Issue (gh issue edit)',
|
||||
)
|
||||
}
|
||||
if (pick.satisfiedWithoutIssue.length > 0) {
|
||||
console.log(
|
||||
` deps sem issue (roadmap entregue, satisfeitas): ${pick.satisfiedWithoutIssue.join(', ')}`,
|
||||
|
|
|
|||
Loading…
Reference in a new issue