Merge pull request #247 from fsolla/cursor/faef5f54

Separate intention plans from engineering execution in agent skills
This commit is contained in:
Francisco Solla 2026-08-02 14:15:07 -03:00 committed by GitHub
commit 13d62bc539
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 622 additions and 695 deletions

View file

@ -11,7 +11,7 @@ description: >-
# Agent pool — operação do supervisor remoto
O pool mantém até **5 Cursor Cloud Agents** (configurável, máx 12) rodando `work-issue` sobre Issues `ready` elegíveis para autonomia. O supervisor é **determinístico** (não é um agente): workflow **`.github/workflows/agent-pool.yml`** (tick stateless a cada 10 min + a cada merge em `main` + sob dispatch) rodando `scripts/agent-pool.mjs`. Arquitetura e elegibilidade: `docs/plans/agent-pool-orchestrator.md`.
O pool mantém até **5 Cursor Cloud Agents** (configurável, máx 12) rodando `agent-work-issue` sobre Issues `ready` elegíveis para autonomia. O supervisor é **determinístico** (não é um agente): workflow **`.github/workflows/agent-pool.yml`** (tick stateless a cada 10 min + a cada merge em `main` + sob dispatch) rodando `scripts/agent-pool.mjs`. Arquitetura e elegibilidade: `docs/plans/agent-pool-orchestrator.md`.
**O pool NUNCA deploya** — deploy gated fica em `ci.yml` após merge em `main`.

View file

@ -0,0 +1,107 @@
---
name: agent-work-issue
description: >-
Executa uma Issue já claimada de ponta a ponta para workers do agent pool:
Plan mode → plano de implementação (engenharia deliberada a partir da
intenção) → execução → /simplify → capture-review-debts → PR Ready em main
com auto-merge. Use quando o pool spawna um worker, quando a Issue já está
in-progress, ou quando o usuário pedir /agent-work-issue.
disable-model-invocation: true
---
# Agent work-issue (autônomo)
Conduz **uma** Issue já claimada do plano de implementação ao merge em `main`. É o contrato dos workers do **agent pool** e a base de execução de `work-issue` (versão humana só adiciona claim + pausa).
**Proibido:** DB de prod / `ALLOW_REMOTE_DB`; merge sem CI green; editar outras Issues `in-progress`; pular `/simplify`; entregar Draft ou sem auto-merge.
**Fonte de produto:** plano de intenção (`docs/plans/<slug>.md`) + body da Issue.
**Fonte de engenharia:** o `*-impl.md` que **você** cria — não o plano de intenção.
## Relação com outras skills
| Skill | Papel |
| ----- | ----- |
| `plan-issue` | Intenção (já feita) |
| **`agent-work-issue` (esta)** | Impl plan → execução → simplify → débitos → PR |
| `work-issue` | Igual, mas claim + **confirmação humana** do impl plan |
## Checklist
```
- [ ] 0. Prep: `pnpm i` se preciso; Cloud → §Prep Cloud (sem Docker)
- [ ] 1. Sessão: rename_chat + open_resource na intenção
- [ ] 2. Modelo (best effort) vs `model:` da Issue
- [ ] 3. Plan mode → plano de implementação (`*-impl.md`)
- [ ] 4. Executar o impl plan (schema/server → UI → gates)
- [ ] 5. /simplify → fixes; capture-review-debts (modo autônomo)
- [ ] 6. PR Ready `--base main` + auto-merge + checks --required
```
## Passo 0 — Prep
```bash
pnpm i # se node_modules ausente/stale
```
### Cloud (sem Docker)
Não use `pnpm db:start`. Postgres via `.cursor/environment.json`. `gate:fast` / `gate:push` não precisam de DB. **Proibido** `git push --no-verify` no fechamento.
## Passo 1 — Sessão (Issue já claimada)
**Não** rode `pnpm agent:claim` — o pool (ou o humano via `work-issue`) já claimou.
1. `rename_chat` → `#<N> <id> — <título>` (padrão canônico; truncar só o título).
2. `open_resource` no plano de intenção (`docs/plans/<slug>.md`).
## Passo 2 — Modelo
Compare `model:` da Issue com a sessão (`model-selection`):
- Sessão mais fraca → informa e segue
- Sessão mais forte → informa; em autonomia do pool, **segue** (o spawn já fixou o modelo)
- Ausente → trate como `composer-2.5`
## Passo 3 — Plano de implementação (Plan mode)
1. `SwitchMode` → `plan` (explique: deliberar engenharia a partir da intenção).
2. Leia [engineering-brief.md](../work-issue/engineering-brief.md) e aplique skills/princípios sob demanda.
3. Explore o código o bastante para **reavaliar** a “Direção no codebase” da intenção — você **deve** escolher a melhor abordagem maintainable, mesmo que difira da hipótese do plano de intenção, desde que o **aceite de produto** se mantenha.
4. Escreva `docs/plans/<slug>-impl.md` via [implementation-template.md](../work-issue/implementation-template.md). Qualidade: [decision-quality.md](../work-issue/decision-quality.md) ≥4/5.
5. Em autonomia: marque Status `aprovado` e **siga sem pausa**. (Em `work-issue`, o humano confirma antes.)
**Divergência material de produto** (aceite/persona/lockdown da intenção não cabem na abordagem): pare, comente na Issue, flip para `blocked` se pool — não invente produto novo.
## Passo 4 — Executar
`SwitchMode` → `agent` se ainda estiver em plan. Ordem:
1. **Schema/server** — migrations (`payload-migrations`), utilities, actions, testes de domínio. Invariantes do engineering-brief.
2. **UI** — se Impeccable B/C/D: shape → craft → critique → polish (harden/optimize só sob gatilho). Tokens `data-theme='campaign'`; shells existentes.
3. **Gates** — `pnpm gate:fast` na iteração; entrega com `pnpm push` (não `git push` nu).
Tracer bullet cedo se o item for grande. Inclua o `*-impl.md` no commit da entrega.
## Passo 5 — `/simplify` + débitos
1. Rode o comando `/simplify` completo (3 reviewers paralelos via Task, read-only) no diff da sessão.
2. Aplique fixes pontuais que preservem comportamento.
3. Rode `capture-review-debts` em **modo autônomo**:
- Colha e pontue como a skill manda
- **Sem** gate humano: registre só `expensive_lock` com score ≥4 (Issues novas com `depends: [<id-pai>]` se necessário)
- Score ≤3 / cheap_polish / defer_trigger → defer com gatilho no `*-impl.md` ou descarte — **não** polua a fila
- Nunca edite a Issue `in-progress` atual para absorver débitos
## Passo 6 — Fechar em main
1. Branch `agent/<id>-<slug>` (worktrees Cursor podem já ter criado).
2. **`pnpm push -u origin HEAD`**
3. PR **Ready** (nunca draft): `gh pr create --base main` com `Closes #<N>` — ou Cloud `ManagePullRequest` com `draft: false`
4. `gh pr merge --auto --merge` imediatamente
5. `gh pr checks <PR> --watch --required` (`checks` + `migration-lock`; ignore Vercel Git)
6. CI flipa `done`/`in-prod` no merge. Comente na Issue o desfecho em uma linha.
## Resumo final
Issue · impl plan (abordagem escolhida + rejeitadas) · o que divergiu da hipótese de direção · simplify + débitos registrados/deferidos · PR + estado do merge.

View file

@ -9,7 +9,7 @@ Após um ciclo de entrega, `/simplify` e `/impeccable` deixam achados **maiores
**Regra inviolável — nunca editar Issue `in-progress`.** Nem para absorver um débito do mesmo pai: registra como **Issue nova** com `depends: [<id-do-pai>]` no frontmatter — assim ela destrava sozinha na fila quando o pai flipar `done` — ou defer com gatilho. Editar a Issue que um agente está executando é esquecimento/conflito garantido.
**Qualidade de decisão:** [decision-quality.md](../plan-issue/decision-quality.md) — caro vs barato, defer+gatilho, depth/YAGNI. Score sozinho não basta: classifique o **tipo de decisão** na triage. Sem tour de fases.
**Qualidade de decisão:** [decision-quality.md](../work-issue/decision-quality.md) — caro vs barato, defer+gatilho, depth/YAGNI. Score sozinho não basta: classifique o **tipo de decisão** na triage. Sem tour de fases.
## Checklist
@ -124,7 +124,7 @@ Mostre ao usuário **antes** de editar docs:
Inclua baldes **já_resolvido**, **descartar** e **defer** com uma linha de racional/gatilho cada (transparência > silêncio).
**Pare e confirme.** Só avance ao Passo 6 com aprovação explícita (ou ajuste pedido). Sem confirmação = não cria Issue nem toca `docs/plans/`.
**Pare e confirme** — exceto em **modo autônomo** (`agent-work-issue` / pool): aí aplique a seção Modo autônomo abaixo e pule o AskQuestion. Só avance ao Passo 6 com aprovação explícita (humano) ou com as regras do modo autônomo. Sem isso = não cria Issue nem toca `docs/plans/`.
## Passo 6 — Registrar via `agent:register` / `agent:file-miss`
@ -139,9 +139,18 @@ Para cada lote com destino **registrar** ou **absorver**:
- **Explicitamente fora** (skips dos revisores + descartes + defers com gatilho deste triage)
6. Self-score de decisão ≥4/5 antes de gravar; classe Impeccable A–D conforme o lote (só-backend = A; UX pós-critique = B/C).
Não implemente as fases aqui. Execução é via `work-issue` (claim → merge em stage), só se o usuário pedir em seguida.
Não implemente as fases aqui. Execução é via `work-issue` / `agent-work-issue`, só se o usuário (ou o pipeline autônomo) seguir.
**Próximo no fluxo de entrega:** após a triage confirmada (ou no-op sem débitos), o fechamento da sessão segue o Passo 6 da skill `work-issue` (fast gate → PR `--base stage` com `Closes #N` → acompanhar CI até o merge).
**Próximo no fluxo de entrega:** após a triage (confirmada ou modo autônomo), o fechamento segue o Passo 6 de `agent-work-issue` / `work-issue` (`pnpm push` → PR `--base main` com `Closes #N` → auto-merge → CI).
## Modo autônomo (`agent-work-issue` / pool)
Quando não há humano no gate (Passo 5):
1. Faça colheita, dedup, score e tipo como de costume.
2. **Registre** só itens `expensive_lock` com score ≥4 (Issue nova + `depends` no pai se preciso; plano curto se score ≥3 eng).
3. Todo o resto → **defer** (gatilho no `*-impl.md` / Explicitamente fora) ou **descartar** — não abra AskQuestion.
4. Resuma no comentário/fechamento o que registrou vs deferiu.
## Anti-padrões (baseline)

View file

@ -50,7 +50,7 @@ Read, in this order:
2. `.cursor/rules/codebase-map.mdc` — dependency direction, where things live, the list system, invariants.
3. `docs/ARCHITECTURE.md` — layers, bounded contexts, decision log.
4. `AGENTS.md` — operational rules + "Recently resolved" history (Pass 1, Pass 2, every post-Pass-2 delivery's /simplify findings).
5. `docs/AGENT-OPS.md` — paradigma de agentes paralelos vigente (claim→PR→stage→promote humano, skills plan-issue/work-issue/project-status). O audit avalia o repo **contra** esse fluxo, não contra o fluxo legacy de roadmap.md.
5. `docs/AGENT-OPS.md` — paradigma de agentes paralelos vigente (claim→PR→main, skills plan-issue / work-issue / agent-work-issue / project-status). O audit avalia o repo **contra** esse fluxo, não contra o fluxo legacy de roadmap.md.
6. `docs/IMPROVE-CODE-QUALITY-PLAN.md` — what the earlier passes already swept. Don't re-register what they fixed; verify fixes held.
7. `docs/TECH-DEBT.md` — open ledger. New findings de-dup against it; verify each open row still exists, close stale ones.
8. `docs/TESTING.md` — safety-net map: what is pinned, where the gaps are.

View file

@ -15,7 +15,7 @@ Production is a live **Neon Postgres** with real citizens' PII. Local developmen
## Cursor Cloud (sem Docker)
VMs Cloud **não rodam** `docker compose` / `pnpm db:start`. Postgres nativo: `.cursor/environment.json` (`cloud-setup.sh` + `ensure-postgres.sh`). Mesmos URLs `localhost:5432/teqo` e `teqo_test`. Agentes em `work-issue`: não tente Docker; `gate:fast`/`gate:push` não precisam de banco.
VMs Cloud **não rodam** `docker compose` / `pnpm db:start`. Postgres nativo: `.cursor/environment.json` (`cloud-setup.sh` + `ensure-postgres.sh`). Mesmos URLs `localhost:5432/teqo` e `teqo_test`. Agentes em `work-issue` / `agent-work-issue`: não tente Docker; `gate:fast`/`gate:push` não precisam de banco.
## Local connection values

View file

@ -58,14 +58,11 @@ Depois de escolher Grok, **obrigatório** pickar um effort. Escreva o slug compl
| `kimi-k3-low` | `kimi-k3` | `reasoning=low` |
| `composer-2.5` | `composer-2.5` | `fast=false` |
## Issues muito complexas (bipartir)
## Issues muito complexas
Quando o blast radius é alto (refactor amplo, simplify repo-wide, migration+RBAC), `plan-issue` **registra duas Issues encadeadas**:
O plano de **implementação** nasce em `work-issue` / `agent-work-issue` (`*-impl.md`), não em `plan-issue`. Preferir **uma** Issue de intenção + Grok no `model:` quando a deliberação de engenharia for cara.
1. `{id}-plan` — `model: cursor-grok-4.5-high` — entregável = plano em `docs/plans/…` + critérios de aceite da execução
2. `{id}` ou `{id}-exec` — `model: kimi-k3-low`, `depends: [{id}-plan]` — executa o plano
Não despachar Kimi K3 Low sem plano fechado na Issue de plan.
Bipartir (`{id}-plan` Grok High → `{id}-exec` `kimi-k3-low`) só sob pedido explícito ou blast radius extremo (refactor repo-wide / simplify amplo). Não despachar Kimi K3 Low sem plano de implementação fechado.
## Regras
@ -86,6 +83,7 @@ Não despachar Kimi K3 Low sem plano fechado na Issue de plan.
## Gates por fluxo
- **`/simplify`:** herda o modelo da sessão. Preferir sessão em Kimi K3 Low **só** quando houver Issue de exec bipartida; caso contrário Composer ou Grok (effort pela tabela) conforme complexidade.
- **`work-issue`:** verifica `model:` da Issue (assimétrico: sessão mais fraca → informa e segue; mais forte → informa e pausa). Ausente → aplica esta tabela **incluindo** o effort Grok.
- **`plan-issue`:** sugere via esta tabela (slug completo com effort); em issues muito complexas, registra o par plan/exec.
- **`work-issue`:** verifica `model:` (assimétrico: mais fraca → informa e segue; mais forte → informa e **pausa**). Ausente → aplica esta tabela.
- **`agent-work-issue`:** pool já fixou o modelo no spawn; sessão mais forte → informa e segue.
- **`plan-issue`:** sugere via esta tabela (slug completo com effort); bipartição só sob blast radius extremo / pedido explícito.
- **`agent-pool` smoke:** Composer default; Grok com effort explícito / Kimi K3 Low em Issues de teste bipartidas.

View file

@ -1,127 +1,125 @@
---
name: plan-issue
description: Registra uma ou VÁRIAS ideias/features/débitos do Teqo como GitHub Issues rastreáveis — classifica, explora o código, produz plano completo em docs/plans/<slug>.md por item (premissas, critérios de aceite, fases verticais, tracer bullet), sugere modelo × effort (model-selection) e passa por um GATE de confirmação (overview + wireframes ASCII + premissas) antes de criar qualquer Issue via `pnpm agent:register`. Usar quando o usuário pedir para adicionar/registrar algo ("adiciona ao roadmap", "registra essa ideia", "cria um plano para", "planeja a issue", "registra tudo isso"), em lote ou avulso.
description: >-
Transforma ideias humanas em Issues GitHub + planos de intenção em
docs/plans/ (persona, fluxo, objetivo, direção suave no código — sem
decisões duras de engenharia). Divide o pedido nas menores tarefas que
ainda fazem sentido. Use quando o usuário pedir /plan-issue, planejar
features, fatiar um pedido em Issues, ou registrar trabalho novo na fila.
disable-model-invocation: true
---
# Planejar e registrar Issues (1..N ideias)
# Planejar Issues (intenção, não engenharia)
Esta skill transforma ideias soltas em: (1) um **plano completo** em `docs/plans/<slug>.md` por item, e (2) uma **GitHub Issue rastreável** por item (`pnpm agent:register`, frontmatter `id/depends/serializes/priority/model`). **GitHub Issues são a fonte canônica** de spec/status/deps/prio/modelo — `docs/roadmap.md` é legado congelado e **nunca** é editado aqui.
Esta skill transforma ideias soltas em: (1) um **plano de intenção** em `docs/plans/<slug>.md` por item, e (2) uma **GitHub Issue rastreável** (`pnpm agent:register`, frontmatter `id/depends/serializes/priority/model`). GitHub Issues são a fonte canônica de spec/status/deps/prio/modelo — `docs/roadmap.md` é legado congelado e **nunca** é editado aqui.
**Gate de confirmação (obrigatório):** nenhuma Issue é criada no GitHub antes do usuário aprovar o overview do lote (Passo 5). Planos locais podem ser rascunhados antes; Issues, não.
**Divisão com `work-issue`:** aqui se classifica a superfície UI (A–D), semeia âncoras de design, escreve o plano (spec + fatias). **Não** se implementa código nem se roda Impeccable craft/critique/polish — isso pertence a `work-issue` (incremental + TDD + gates).
## Divisão com as skills de execução
**Mapa das skills de planejamento:** o que absorver vs. rotear — [skills-map.md](skills-map.md). Princípios em silêncio; sem tour.
| Skill | Papel |
| ----- | ----- |
| **`plan-issue` (esta)** | Intenção humana: o quê / para quem / por quê / outcome. Direção suave no codebase. **Proibido** travar schema, signatures, migrations, abstrações ou “Abordagem” de engenharia. |
| **`work-issue`** | Humano supervisiona: claim → plano de **implementação** (Plan mode) → **pausa** para confirmação → executa. |
| **`agent-work-issue`** | Pool / autonomia: Issue já claimada → plano de implementação → executa sem pausa → `/simplify` → `capture-review-debts` → PR Ready + auto-merge. |
**Qualidade de decisão (não é tour):** aplique [decision-quality.md](decision-quality.md) em silêncio — filtro caro vs barato, Opções+Recomendação+rejeitadas, appetite, rabbit holes, depth check, fatias verticais, doubt em decisão cara, self-score ≥4 antes de gravar.
Aqui **não** se implementa código, **não** se escreve plano de implementação, **não** se roda Impeccable craft/critique/polish.
**Dados → decisão → apresentação:** se o item produz, agrega ou exibe números/séries/mapas/KPIs, aplique [data-presentation.md](data-presentation.md) em silêncio antes de travar a Abordagem. Se não há superfície de dados, `Dados: N/A` no plano.
**Shaping (não tour):** aplique [shaping.md](shaping.md) em silêncio — appetite, fatia mínima útil, rabbit holes de produto, self-score ≥4 antes de gravar.
## Checklist do fluxo
**Dados (intenção):** se o item envolve números/KPIs/mapas, aplique [data-presentation.md](data-presentation.md) só até “quem decide o quê com este dado”. A **forma** (chart/mapa/KPI) fica para o plano de implementação.
## Checklist
```
- [ ] 1. Parse do lote + dedup (intra-lote, Issues existentes, docs/plans, roadmap legacy)
- [ ] 1b. Clareza: ideia vaga → idea-refine leve / perguntar; senão premissas explícitas
- [ ] 2. Reserva de IDs de uma vez por trilha (roadmap legacy + issuesById())
- [ ] 3. Por item (ordem topológica): classificar → explorar código → Impeccable A–D → dados
→ decisões (doubt se caro) → fases verticais + tracer → posicionamento → plano completo
- [ ] 3. Por item (ordem topológica): classificar → fatiar → explorar só o suficiente → intenção completa
- [ ] 4. Sugestão de modelo × effort via model-selection (uma linha por item)
- [ ] 5. GATE: overview do lote + premissas + wireframes ASCII (B/C/D) → confirmar/iterar
- [ ] 6. Registro: pnpm agent:register (com --model) por item + commit dos planos
- [ ] 5. GATE: overview do lote + esboços de fluxo (B/C/D) → confirmar/iterar
- [ ] 6. Registro: pnpm agent:register (com --model) por item + commit dos planos de intenção
```
## Passo 1 — Parse do lote e dedup
## Passo 1 — Parse e dedup
1. **Separe os itens.** A entrada pode vir como 1 ideia ou N (lista, parágrafo, notas). Se a separação for ambígua, assuma a leitura mais provável e liste como você entendeu — a confirmação vai junto do gate.
2. **Deduplique dentro do lote.** Desfechos: **mesclar** (um item, plano único), **absorver** (vira fase de plano existente, sem ID novo), ou **manter separados** com dependência explícita.
3. **Deduplique contra o que já existe:** `gh issue list --state all` (frontmatter `id` via `issuesById()` em `scripts/lib/agent-github.mjs`), grep em `docs/plans/*.md` e em `docs/roadmap.md` (legado). Três desfechos por item: **já coberto** → aponte a Issue/plano existente e não crie nada; **é fase de plano existente** → adicione ao plano existente; **realmente novo** → siga.
## Passo 1b — Clareza e premissas (antes de reservar ID / escrever plano)
Inspirado em `idea-refine` + `spec-driven-development` + `using-agent-skills` (“Surface Assumptions”) — **leve**, sem sessão divergente completa.
1. **Ideia ainda vaga?** (não dá para escrever Objetivos testáveis, persona, ou 1 fatia vertical). Desfechos:
- **Roteiar** para `idea-refine` / `interview-me` se o usuário quiser explorar; ou
- **Uma rodada** de 3–5 sharpening questions (quem, sucesso, constraints, o que já tentou, por quê agora) + recomendação; **não** avance ao Passo 2 até haver um HMW / problema em uma frase e um MVP óbvio.
2. **Premissas explícitas.** Antes de redigir o plano, liste o que está assumindo (produto, schema, papel, escopo). Formato no plano e no gate:
```text
PREMISSAS:
1. …
2. …
→ Corrija agora ou sigo com estas.
```
Não preencha ambiguidade em silêncio. Assunções que forem default de produto ficam marcadas _(assumido — validar com produto)_ nas Questões em aberto.
3. **Pedido vago → critérios de sucesso.** Reframe (“deixar o dashboard mais rápido”) em condições testáveis antes da Abordagem. Se não der para medir/verificar → ainda está vago (voltar ao item 1).
1. **Separe os itens.** Entrada pode ser 1 ideia ou N. Se ambíguo, assuma a leitura mais provável e liste — a confirmação vai no gate.
2. **Fatia mínima útil.** Prefira várias Issues pequenas a um epic. Cada item deve caber num appetite curto e entregar um outcome verificável sozinho. Mesclar só quando separar criaria trabalho inútil (mesmo fluxo, mesma persona, mesma superfície sem valor incremental).
3. **Dedup intra-lote:** mesclar | absorver (fase de plano existente, sem ID novo) | manter separados com `depends`.
4. **Dedup contra o existente:** `gh issue list --state all` + `issuesById()` + grep em `docs/plans/*.md` e `docs/roadmap.md` (legado). Já coberto → apontar e não criar; fase de plano existente → editar aquele plano; novo → seguir.
## Passo 2 — Reserva de IDs
Levante o último ID usado por trilha (A/B/C/D/E) olhando o roadmap legacy + `issuesById()` e distribua sequencialmente para os itens do lote **antes de escrever qualquer plano** (ex.: trilha B em `B78` → os dois itens de B viram `B79`, `B80`). IDs fora de trilha (chore/ops) seguem o prefixo do seu domínio conforme precedentes (`O0+`, `FD+`, `RS+`) ou a trilha temática mais próxima.
Último ID por trilha (A/B/C/D/E) via roadmap legacy + `issuesById()`; distribua **antes** de escrever planos. Fora de trilha: prefixos `O0+`, `FD+`, `RS+` ou trilha temática mais próxima.
## Passo 3 — Por item: do tipo ao plano completo
## Passo 3 — Por item: intenção completa
Ordem topológica intra-lote (o plano do dependente cita o ID do dependido, que já existe). Por item:
Ordem topológica (dependente cita ID do dependido). Por item:
1. **Classificar o tipo:**
1. **Tipo**
| Tipo | Destino |
| ---- | ------- |
| Feature de `/campanha` ou site público com escopo próprio | Issue `kind:feature` com plano |
| Tarefa pequena / chore / débito de engenharia | Issue `kind:chore` + plano curto (ou body direto se trivial) |
| Défice comportamental do fluxo de agentes | `pnpm agent:file-miss` (`kind:agent-miss`), não aqui |
| Bloqueio externo (jurídico/LGPD) | Issue `blocked` + label `needs:consent`/`needs:migration`; texto novo entra no lote jurídico existente, nunca rodada separada |
| Evidência de usuário ainda inexistente (discovery) | `blocked` / defer+gatilho — não inventar feature; ver `continuous-discovery` só se o usuário pedir discovery |
| Feature `/campanha` ou site com escopo próprio | `kind:feature` + plano de intenção |
| Chore / débito pequeno | `kind:chore` + plano curto (ou body se trivial) |
| Défice do fluxo de agentes | `pnpm agent:file-miss` (`kind:agent-miss`) — não aqui |
| Bloqueio externo (jurídico/LGPD) | `blocked` + `needs:consent`/`needs:migration`; texto no lote jurídico existente |
| Decisão de NÃO fazer | Comentário/doc, não Issue |
2. **Explorar o código** (depth check): onde a feature se pluga, o que reusar de `src/utilities/*`, `src/components/campaign/*`, `src/lib/*`; schema novo → migration (caro de reverter → Decisão travada com rejeitadas); pessoa → join com `Contact`; opt-in/PII → `Consent` por chave estável falhando fechado. Precedente análogo em `docs/plans/` dita o nível de detalhe. Cite **caminhos reais** (context-engineering: plano legível sem dump do repo).
3. **Classificar superfície UI (A–D)** e semear âncoras: `PRODUCT.md`/`DESIGN.md`, design-ref em `docs/design-refs/latest/` se houver, shells existentes. Classe C exige **brief compacto** (persona, job, estratégia de cor, anti-goals) no plano. Proibido: rodar craft/critique/polish aqui.
4. **Dados → decisão → apresentação** ([data-presentation.md](data-presentation.md)) ou `Dados: N/A`.
5. **Decisões caras + doubt (quando couber):** para cada decisão caro-de-reverter (schema, access, Consent, URL imutável, multi-collection), use a forma Opções+Recomendação+rejeitadas. Se a decisão for **não trivial** no sentido de [decision-quality.md](decision-quality.md) § Doubt, faça um ciclo curto CLAIM → adversarial self-check (ou `Task` fresh-context) **antes** de gravar como Decisão travada. Não doubt em rename/copy.
6. **Posicionamento:** prioridade `P0..P3` (jurídico/caminho crítico > base de dados > operação de campo > inteligência > plataforma), `depends` (IDs duros), appetite, janela do calendário eleitoral quando relevante, `serializes` quando toca recurso compartilhado (ex.: migrations).
7. **Fatiar em fases verticais** ([decision-quality.md](decision-quality.md) § Fatias): não “toda a DB → toda a API → toda a UI”. Cada fase = caminho fino ponta a ponta (ou o pedaço mínimo que deixa o sistema verde), com **aceite**, **verify** (`pnpm gate:fast` / pin unit|int / check manual), arquivos prováveis, tamanho S/M. **Fase 1 = tracer bullet** (schema mínimo → uma action → uma superfície, ou o menor path que prova a aposta). High-risk / incerteza primeiro. Se a fatia seria L/XL (≫5 arquivos ou >1 sessão focada) → mais fases **ou** Issue bipartida `{id}-plan` / `{id}-exec`.
8. **Boundaries Teqo** no plano (sempre, compacto): o que esta entrega **Always** / **Ask first** / **Never** — ver template. Defaults do repo (overrideAccess, transação, Consent fail-closed, sem Neon) entram em Always/Never sem inventário genérico.
9. **Source-driven (flag, não fetch):** se a Abordagem depende de API de framework (Payload Local API, Next App Router, WebAuthn), anote na fase: “na implementação, verificar docs oficiais da versão em `package.json`” — o fetch é de `work-issue` / `source-driven-development`.
10. **Plano completo** em `docs/plans/<slug>.md` seguindo [plan-template.md](plan-template.md) à risca — cabeçalho, Premissas, Objetivos como aceite, Decisões, Fases verificáveis (quota do appetite), Dados, wireframe ASCII se B/C/D com layout, guardrails, rabbit holes, adiados. Self-score ≥4/5 antes de gravar.
2. **Explorar o código o mínimo** — só para apontar **direção** (rotas/pastas/domínios prováveis) e evitar duplicar algo já entregue. Não inventar signatures, collections novas como decisão travada, nem diagramas de componentes.
3. **Superfície UI (A–D)** como dica para quem for executar — não semear brief Impeccable completo nem wireframe de implementação. Classe C/D: esboço de fluxo persona (ASCII curto) no gate, não especificação de layout.
4. **Dados (intenção)** ou `Dados: N/A`.
5. **Posicionamento:** `P0..P3`, `depends`, appetite, janela eleitoral se relevante, `serializes` se tocar recurso compartilhado (ex. migrations) — sem detalhar a migration.
6. **Plano de intenção** em `docs/plans/<slug>.md` via [intention-template.md](intention-template.md). Self-score ≥4/5 ([shaping.md](shaping.md)).
## Passo 4 — Sugestão de modelo × effort
### O que é proibido no plano de intenção
Aplique a skill `model-selection` (tabela canônica) por item e registre a sugestão no cabeçalho do plano (`Model:`) e no resumo do gate. Caminho feliz único:
- Decisões de schema / collection / unicidade / Consent key concreta como “travadas”
- Assinaturas de funções, nomes de arquivos novos obrigatórios, mermaid de arquitetura de solução
- “Abordagem proposta” com componentes e migration nomeada
- Fases de implementação verificáveis com quota de engenharia
- Forçar o executor a uma única forma técnica
- `composer-2.5` — default (features, chores simples, fixes localizados, docs leves)
- `cursor-grok-4.5-low` | `cursor-grok-4.5-medium` | `cursor-grok-4.5-high` — Grok com **effort explícito** (ver model-selection: Low = mecânico com julgamento; Medium = discovery/análise; High = multi-domínio / falha cara)
- `kimi-k3-low` — **só** fase de execução de issues bipartidas (refactor / simplify / migration+RBAC de blast radius alto)
### O que é obrigatório
**Issues muito complexas:** registre **duas** Issues encadeadas — `{id}-plan` (`model: cursor-grok-4.5-high`, entregável = plano + critérios de aceite) e `{id}`/`{id}-exec` (`model: kimi-k3-low`, `depends: [{id}-plan]`). O valor vai ao frontmatter `model:` — propriedade da Issue, verificada (não recalculada) por `work-issue`.
- Intenção do humano (problema/oportunidade)
- Persona(s) e fluxo desejado (job / outcome)
- Critérios de aceite em linguagem de produto
- Appetite e fora de escopo (produto)
- **Direção provável no codebase** (pastas/rotas/domínios — hipotética, revisável)
- Questões em aberto com **Opções + Recomendação de produto** (não de engenharia)
## Passo 5 — GATE de confirmação (obrigatório)
## Passo 4 — Modelo × effort
Apresente no chat, **antes de criar qualquer Issue**:
Skill `model-selection`. Registre no cabeçalho (`Model:`) e no gate.
- **Overview do lote** — uma linha por plano: ID, título, prio, depends, appetite, modelo sugerido, link do plano local.
- **Premissas** por item (ou bloco compartilhado do lote) — “corrija agora ou sigo”.
- **Wireframes ASCII** das superfícies B/C/D (copiados dos planos).
- **Fases em uma linha** (F1 tracer → …) quando o item tiver >1 fase.
- Perguntas acumuladas (se houver) em uma única rodada, recomendação primeiro.
- Default: `composer-2.5`
- Grok com effort explícito quando discovery/multi-domínio / falha cara de **produto**
- Não crie par `{id}-plan` / `{id}-exec` por default — o plano de implementação nasce em `work-issue` / `agent-work-issue`. Reserve bipartição só para blast radius extremo (refactor repo-wide) se o humano pedir.
O usuário confirma ou pede modificações; itere até confirmar. **Só depois** avance ao Passo 6. Planos em `docs/plans/` podem ser rascunhados antes do gate (arquivos locais isolados); ajuste-os conforme a resposta.
## Passo 5 — GATE
Antes de criar Issues:
- Overview: ID, título, prio, depends, appetite, modelo, link do plano local
- Esboços de fluxo persona para superfícies B/C/D (se houver)
- Perguntas acumuladas numa rodada, recomendação de produto primeiro
Itere até confirmação. Só então Passo 6.
## Passo 6 — Registro
Por item confirmado:
```bash
pnpm agent:register -- --id <ID> --title "<título>" --prio <P0..P3> \
--depends <A,B> --kind <feature|chore|...> --plan docs/plans/<slug>.md \
--model <slug> [--blocked] [--labels extra]
```
A Issue nasce `ready` (ou `blocked`) com frontmatter `id/depends/serializes/priority/model` + spec + link do plano. Atualize o cabeçalho do plano (`Issue: #N`). Commit dos planos (commits lógicos por item ou por lote).
Atualize `Issue: #N` no plano. Commit dos planos de intenção.
**PR só de plano (`docs/plans/` exclusivamente):** nunca use `Closes #N` / `Fixes` / `Resolves` no body — use `Related #N`. O CI (`plans-only-closes`) bloqueia keywords de fechamento; a implementação fecha a Issue em outro PR (`work-issue`).
**PR só de plano:** nunca `Closes #N` — use `Related #N` (`plans-only-closes`).
**NÃO faz:** editar `docs/roadmap.md` (legado congelado), implementar código, claim (`pnpm agent:claim` é de `work-issue`), abrir jornada `design-code-architecture`, gravar `tasks/plan.md` / `tasks/todo.md` (artefato Teqo = `docs/plans/<slug>.md`).
**NÃO faz:** editar `docs/roadmap.md`, implementar, claim, escrever `*-impl.md`.
## Resumo final
Tabela do lote (ID, título, prio, depends, appetite, modelo, Issue #N, plano) + em prosa: mesclados/absorvidos/descartados por duplicidade, premissas que o gate confirmou ou corrigiu, decisões assumidas _(validar com produto)_, e o que o gate decidiu.
Tabela do lote + mesclados/absorvidos/descartados + decisões de produto assumidas _(validar)_ + o que o gate decidiu.

View file

@ -1,112 +1,39 @@
# Dados → decisão → apresentação
# Dados → decisão (intenção) → forma (implementação)
Filtro obrigatório quando um item do roadmap **produz, agrega ou exibe** números, séries, rankings, mapas ou KPIs. Inspirado em `visualization-choice-reporting` (pergunta → tipo de chart → narrativa acionável) e no kernel Teqo (`PRODUCT.md` §5 + `docs/research/`). **Não** é um tour de dashboard design — são três perguntas com resposta registrada no plano. Decisão silenciosa (“só coloca um gráfico”) é defeito.
Quando um item **produz, agrega ou exibe** números, séries, rankings, mapas ou KPIs. Kernel Teqo: `PRODUCT.md` §5 + `docs/research/` — disputa de DF é relativa/local, não % estadual absoluto.
Aplique em silêncio em `plan-issue` (ao semear o plano) e em `work-issue` (ao auditar e fatiar UI). Se o item **não** apresenta dados (ex.: migration de Consent, invite WhatsApp, form CRUD sem métrica), escreva `Dados: N/A` no plano e pule o resto.
| Fase | Skill | O que decide |
| ---- | ----- | ------------ |
| Intenção | `plan-issue` | Vou apresentar dados? Quais **decisões de ator** isso desbloqueia? Restrições de produto. |
| Implementação | `work-issue` / `agent-work-issue` | Forma concreta (número+contexto / lista / série / mapa / chart) + rejeitadas técnicas. |
## As três perguntas (ordem fixa)
Se o item **não** apresenta dados: `Dados: N/A` no plano de intenção e pule o resto.
Responda nesta ordem. Pular para “qual chart?” antes de fechar (1)–(2) é o erro clássico.
## Na intenção (`plan-issue`)
Ordem fixa:
```text
1. Vou apresentar dados?
2. Quais decisões serão tomadas a partir destes dados?
3. Como apresentar estes dados para auxiliar essa decisão de forma efetiva?
```
### 1. Vou apresentar dados?
| Resposta | Critério | Ação no plano |
| ------------------------------ | ---------------------------------------------------------------------- | ------------------------------------------------- |
| **Não** | Só schema/action/access; nenhum número lido por humano nesta entrega | `Dados: N/A` — fim |
| **Sim, derivado / API só** | Utility/aggregate que **outra** superfície já consome (ou item futuro) | Registrar payload + quem consome; UI fica no dono |
| **Sim, superfície neste item** | Lista, detalhe, dashboard, mapa, CSV export legível, card de insight | Preencher seção completa abaixo |
| Resposta | Ação |
| -------- | ---- |
| **Não** | `Dados: N/A` |
| **Sim, derivado / API só** | Registrar quem consome; UI no dono |
| **Sim, superfície neste item** | Preencher decisões desbloqueadas + restrições |
Se “sim”: profile rápido do dado — tipo (categórico / numérico / temporal / geo), granularidade (praça / município / TI / estado), tamanho típico (1 KPI vs 436 linhas vs série 3 anos), e se é **absoluto ou relativo** (no `/campanha` electoral, preferir relativo/local — ver anti-goals).
Profile rápido (opcional): tipo / granularidade / absoluto vs relativo.
### 2. Quais decisões serão tomadas a partir destes dados?
### 2. Decisões desbloqueadas
Uma frase por decisão, no formato **ator + escolha**. Sem decisão nomeável → o dado é vaidade; corte ou rebaixe a “contexto secundário”.
Formato **ator + escolha**. Sem decisão nomeável → vaidade; corte.
Exemplos Teqo bons:
**Não** escolha chart/mapa/KPI aqui. Registre só anti-goals de produto (ex.: sem gauge SaaS, sem % estadual absoluto).
- Coordenador: “nesta semana, atacar déficit descoberto em quais Praças?”
- Assessor: “minha meta fecha? se não, renegociar pledge ou abrir demanda?”
- Staff: “comparar candidato X vs Solla neste município — manter ou pivotar discurso?”
## Na implementação (`*-impl.md`)
Exemplos ruins (rejeitar):
- “Ter visibilidade do % estadual” (anti-goal; não decide alocação)
- “Ver quantos apoiadores cadastrados” sem vínculo a cobertura/meta
- “Dashboard bonito para impressionar”
Se o item toca inteligência de campanha / mapa / metas / fila: consulte **antes** o playbook em `docs/research/relatorio-entrevista-persona-campanha.md` (§6 padrões dado→decisão) e o anti-catálogo do plano-mestre `docs/plans/inteligencia-campanha.md`. Não invente métrica que o research vetou.
### 3. Como apresentar para auxiliar essa decisão?
Escolha a **forma mais pobre que ainda responde a decisão** (depth: reusar shell existente > chart novo > lib de charts). Registre no plano: forma + racional + o que foi rejeitado.
**Escada de pobreza (preferir o degrau mais baixo que resolve):**
| Degrau | Quando usar | Reuso Teqo típico |
| ------------------------------ | ----------------------------------------------------------------- | ----------------------------------------------------- |
| **Número + contexto** | 1–2 valores, “fecha / não fecha”, delta vs meta/semana | `CampaignMetricStrip`, linha no overview |
| **Tabela / lista ranqueada** | Comparar muitas entidades (Praças), ordenar por déficit/cobertura | `PlazaList` + colunas; fila de alocação |
| **Série temporal simples** | Evolução curta (3–5 pontos: 2014/2018/2022 ou delta semanal) | sparkline / tabela ano×valor; não multi-eixo |
| **Mapa (cor / símbolo)** | Decisão é **onde** agir; geo é central à pergunta | `BahiaMap` + escala relativa (quantil/LQ), não % est. |
| **Chart (barra / linha)** | Comparação de poucas categorias ou tendência com >~5 pontos | shadcn/`src/components/ui`; tokens `campaign` |
| **Chart composto / dashboard** | Só se appetite e research pedirem; senão rabbit hole | Adiar com gatilho |
**Família de pergunta → forma** (resumo de visualization-choice-reporting, calibrado ao Field Desk):
| Pergunta que o dado responde | Preferir | Evitar neste produto |
| ---------------------------------- | -------------------------------- | ----------------------------------- |
| Quanto falta / cobre a meta? | Número + % cobertura + delta | Gauge/velocímetro SaaS, hero-metric |
| Onde está o buraco / oportunidade? | Mapa relativo ou lista ranqueada | Choropleth de % estadual absoluto |
| Como evoluiu no tempo? | Linha/sparkline ou tabela anos | Pie; dual Y-axis |
| Como A se compara a B (poucos)? | Barra horizontal ou tabela | Pie com muitas fatias; 3D |
| Qual a composição do todo? | Stacked bar ou tabela | Donut decorativo |
| Correlação / nuvem de pontos? | Quase nunca em v1 `/campanha` | Scatter exploratório sem decisão |
**Narrativa mínima na UI** (mesmo sem relatório formal): o bloco de dados deve permitir ler, nesta ordem — **insight → padrão → contexto (vs meta/histórico) → implicação → próxima ação possível**. Título descritivo (“Votos por mês”) sem insight é falha. Em `/campanha`, a “ação” é menu para julgamento humano (nunca auto-decisão) — alinhado ao research.
## Anti-goals Teqo (não negociar sem fonte nova)
- KPI de **% estadual absoluto** como escala principal (achatamento; DF ≠ majoritária).
- Contagem bruta de cadastros / “vanity metrics” sem vínculo a cobertura/meta/fila.
- Cartograma, gauge, rainbow choropleth, dual-axis enganoso.
- Mapa bonito com pergunta errada (visualização serve à análise; análise serve à decisão — research § ordem Brewer/Pickle).
- Segunda lib de charts / design system paralelo; inventar paleta fora de `data-theme='campaign'`.
- Sugestão automática sem registro de decisão humana (C12 / motor de sugestões).
## Quando NÃO usar gráfico
- Um único número decisivo → número tipográfico + unidade + vs quê.
- Dois números → lado a lado com delta %.
- Poucas linhas densas de auditoria → tabela.
- Export/CSV para operação → tabela; chart é opcional depois.
## Caro vs barato nesta superfície
| Caro (Decisão travada + rejeitadas) | Barato (Não escopo / Adiado) |
| ------------------------------------------------ | ----------------------------------------- |
| Métrica canônica (fórmula, denominador, quem vê) | Cor da barra, ordem de colunas |
| Escala do mapa (absoluta vs % vs quantil/LQ) | Tooltip copy |
| Staff-only vs leader-visible | Sparkline vs número só |
| Persistência de derivado vs compute on read | Biblioteca de chart (se já há shadcn/SVG) |
## Self-check (30s, só se Dados ≠ N/A)
Antes de gravar o plano ou declarar a fase de UI pronta — 1 ponto cada; **&lt;3 → corrigir**:
1. As três perguntas estão respondidas por escrito?
2. Há pelo menos uma **decisão nomeável** (ator + escolha)?
3. A forma escolhida é o degrau mais pobre que resolve — com alternativas rejeitadas?
4. Anti-goals do research/`PRODUCT.md` §5 não foram violados?
5. Depth: reusa `CampaignMetricStrip` / lista / `BahiaMap` / tabela existente quando bastam?
## Onde registrar
- **`plan-issue`:** seção **Dados → decisão → apresentação** no `docs/plans/<slug>.md` (template). Se N/A, uma linha basta.
- **`work-issue`:** auditar essa seção no Passo 4; se ausente e o item claramente apresenta dados → defasado (completar no Passo 7). Nas fases de UI, a escolha de forma é input do craft/critique — não reinventar no meio do polish.
- Skills externas (opcional, leitura sob demanda): `visualization-choice-reporting` (famílias de chart + narrativa); `.agents/skills/refactoring-ui/references/data-visualization.md` (quando NÃO chartar); Mapbox patterns só se o item for mapa Mapbox (hoje o mapa Teqo é Leaflet/`BahiaMap`).
Responda a pergunta 3 com Opções + Recomendação + rejeitadas, alinhado a [decision-quality.md](../work-issue/decision-quality.md) e ao research Teqo. Preferir a forma mais pobre que ainda desbloqueia a decisão.

View file

@ -1,147 +0,0 @@
# Qualidade de decisão (roadmap / implementação / débitos)
Inspirado em `design-code-architecture` e nas skills que ela compõe (37signals, software-design-philosophy, clean-architecture, DDD), mais destilados de `spec-driven-development`, `planning-and-task-breakdown`, `incremental-implementation` e `doubt-driven-development` — **sem** jornada guiada por fases. Use estes filtros automaticamente ao redigir planos, implementar ou triar débitos. Decisão silenciosa é defeito.
Mapa completo do que absorver vs. rotear: [skills-map.md](skills-map.md).
## Filtro caro vs barato
Delibere e registre só o **caro de reverter**. O barato vira Não escopo, fill-in, ou “mais simples que funciona” com **gatilho de revisitação** (não “depois”).
| Caro (decidir agora + alternativas rejeitadas) | Barato (adiar / mais simples) |
| ------------------------------------------------------------------------ | ----------------------------------- |
| Collection nova, unicidade, modelo de access | Polish cosmético, 2º estilo de card |
| Nova chave `Consent` / superfície PII | Copy, motion, a11y P3 |
| Semântica de escrita multi-collection / locks | Prefetch, apresentação de KPI |
| URL pública / slug imutável | Ordem de colunas na lista |
| Separar item de trilha vs absorver em plano | Rename de pureza, naming cosmético |
| Fronteira de módulo em ponto de volatilidade real (DB, vendor, delivery) | Adapter/interface com 1 call site |
Converter caro em barato: colocar um boundary na frente (fail-closed por chave, join em `Contact`, chips opt-in em vez de igualdade forçada) — o conjunto irredutível de decisões caras deve caber nas Decisões travadas.
## Forma obrigatória de decisão
Toda decisão não trivial (posicionamento, classe Impeccable B↔C, absorver vs registrar, default de produto, schema vs não):
```text
Opções: A | B | C
Recomendação: B — porque …
Alternativas rejeitadas: A porque …; C porque …
```
No plano: Decisões travadas = **decisão + por quê + fonte/data + alternativas rejeitadas**. Em Questões em aberto: **Opções + Recomendação** (nunca pergunta sem posição). Assuma o default e marque _(assumido — validar com produto)_ — não abra tour de confirmações.
## Premissas (antes da Abordagem)
Não preencha ambiguidade em silêncio. Liste premissas no plano e no gate:
```text
PREMISSAS:
1. …
→ Corrija agora ou sigo com estas.
```
Pedido vago → **reframe em critérios de aceite testáveis** antes de desenhar componentes. Se não dá para marcar um checkbox de Objetivo ao fim da Issue, a ideia ainda não está shaped (Passo 1b / `idea-refine`).
## Appetite (tempo fixo, escopo flexível)
Além da **janela** eleitoral, declare um **appetite** (quanto o slice vale), não uma estimativa aberta:
- Exemplos: `~0,5 dia eng, só utility` · `~1–2 dias, migration + 1 action + encaixe em lista` · `~1 ciclo curto, UI nova 1 rota`.
- Se a Abordagem proposta estourar o appetite → cortar rabbit holes / Não escopo, não inflar o item.
- Em `work-issue`, cada fase declara quanto do appetite consome; preferir um **tracer bullet** cedo (schema → uma action → uma superfície UI) antes de polish paralelo.
## Fatias verticais (fases do plano)
De `planning-and-task-breakdown` + `incremental-implementation` — no artefato Teqo (`docs/plans/`), não em `tasks/todo.md`.
**Ruim (horizontal):** schema completo → todas as actions → toda a UI → “ligar”.
**Bom (vertical):** Fase 1 prova um path fino ponta a ponta; Fase 2 alarga.
Regras:
1. **Ordem = grafo de dependência**, não “o que parece importante”. Fundações (migration, access) só o mínimo para o tracer.
2. **Cada fase** tem aceite (≤3 bullets), verify (comando/pin), files, tamanho **S** (1–2 files) ou **M** (3–5). **L/XL** → partir a fase ou bipartir a Issue.
3. **Fase 1 = tracer bullet** (ou risk-first se a aposta arriscada for outra — ex. provar WebAuthn antes do chrome).
4. Após cada fase o sistema deve permanecer **compilável / testes verdes** (disciplina de `work-issue`).
5. Checkpoint humano só quando o plano tiver >2 fases ou uma decisão cara ainda aberta — não cerimônia entre S chores.
## Doubt em decisão cara (ciclo curto)
De `doubt-driven-development` — **só** quando a decisão é não trivial **e** cara de reverter (branching de access, migration irreversível, invariante que o type system não pega, URL pública).
```text
CLAIM: <1–2 linhas>
WHY IT MATTERS: <blast radius>
→ Adversarial self-check (ou Task fresh-context): achar furos no ARTIFACT+CONTRACT,
não validar. Classificar: actionable | trade-off documentado | noise.
→ Parar em 1 ciclo no planning (3 ciclos é para implementação).
```
Não doubt: rename, copy, chore mecânico, “seguimos o shell de lista existente”.
Não invocar cross-model CLI daqui — se o usuário quiser segunda opinião, ofereça no gate.
## Rabbit holes
Riscos que explodem o escopo se tocados “de passagem”. Listar ao lado de Não escopo (não são a mesma coisa):
| Não escopo | Rabbit hole |
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Exclusão consciente com destino (outro plano/ID) | Armadilha se alguém “só completar” |
| Ex.: mapa Leaflet → B3 | Ex.: layers Clean Architecture só para um feature; 2ª collection de pessoa; igualdade forçada TSE; event sourcing; helper shared antes de 3 call sites |
Rabbit holes Teqo recorrentes: layers/cerimônia sem volatilidade, cadastro paralelo a `Contact`, Consent hardcoded por ID, abstração DRY prematura, redesign de paleta fora de `campaign`.
## Depth check (módulos profundos)
Antes de propor arquivo/utility/componente novo na Abordagem:
1. Já existe módulo profundo que esconde isso? (`campaignAccess`, shells de lista, `withPayloadTransaction`, `campaignConsent`, …) → **reusar**.
2. O novo símbolo esconde complexidade real ou é pass-through raso (classitis)? → **consolidar ou não criar**.
3. Uma decisão de design vazaria em N módulos? → **encapsular uma vez**.
Não invocar a skill `software-design-philosophy` inteira — aplicar só este check no momento da decisão.
## Defer com gatilho
Adiar sem gatilho vira backlog morto. Formato:
`Adiar X até <evidência concreta>` — ex.: “shared `drizzleBulk` quando existir o 3º caminho bulk”; “réplicas/cache quando QPS médio > N” (raro neste produto).
Em `capture-review-debts`: DRY com &lt;3 call sites → preferir **descartar** ou **defer+gatilho** a **registrar**, salvo access/LGPD/hot path.
## Boundaries Always / Ask / Never (por entrega)
Compacto no plano — reforça o que **esta** Issue carrega; não reescrever AGENTS.md.
| Tier | Exemplos Teqo típicos |
| ----------- | ------------------------------------------------------------------------------------- |
| **Always** | `overrideAccess: false` com `user`; pin de teste do parser/access; fail-closed Consent |
| **Ask first** | Collection/migration nova; dependency nova; mudar contrato de URL pública |
| **Never** | Neon em dev/test; Consent por document ID; pessoa fora de `Contact`; `as never` |
## Princípios sob demanda (método, não jornada)
Quando o tipo de decisão bater, aplicar o princípio — **não** abrir fases de `design-code-architecture`:
| Tipo de decisão | Princípio |
| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| Dependências de código / testabilidade do domínio | Dependency Rule: framework/ORM no anel externo; core testável sem DB/web |
| Vocabulário / aggregate / “Customer” em dois sentidos | DDD: não unificar; invariants no aggregate; refs por ID |
| Escopo de v1 do item | 37signals: build less, YAGNI, cortar abstração especulativa; **nunca** cortar o caro de reverter |
| Depth / leakage na abordagem | software-design-philosophy: deep modules, um lugar por conhecimento |
| Outbound / lista / import | Timeouts, paginação, fail-closed (já em AGENTS.md) — nomear como decisão se o item toca |
| KPI / mapa / série / ranking na UI | [data-presentation.md](data-presentation.md): dado → decisão nomeável → forma mais pobre |
| API de framework na Abordagem | Flag source-driven para `work-issue` (versão em package.json); não inventar da memória no plano |
## Self-score (gate de 30s)
Antes de gravar docs ou declarar o plano de implementação pronto, pontue 0–5 (1 ponto cada). **&lt;4 → corrigir antes de escrever/seguir**:
1. Decisões caras têm alternativas rejeitadas (e doubt curto se migration/access/Consent/URL)?
2. Appetite declarado; fases verticais cabem nele; Fase 1 = tracer (ou risk-first justificado)?
3. Premissas listadas + Objetivos como aceite testável + Boundaries Always/Ask/Never?
4. Rabbit holes nomeados (além de Não escopo) + depth check (reusa shells, sem classitis)?
5. Consistência aplicável: tripla grafo=tabela=Dependências **ou** triage score/destino/tipo alinhados?
Opcional no resumo ao usuário: `Qualidade de decisão: N/5` + o item que falhou.

View file

@ -0,0 +1,89 @@
# Template de plano de intenção (`docs/plans/<slug>.md`)
Plano de **produto/intenção** — o que o humano quer, para quem, e como saber que deu certo. **Não** é plano de engenharia: quem executa (`work-issue` / `agent-work-issue`) cria o `docs/plans/<slug>-impl.md` depois, com liberdade de reavaliar a abordagem técnica.
Shaping: [shaping.md](shaping.md). Dados (só decisão de produto): [data-presentation.md](data-presentation.md).
````markdown
# <Título do item em pt-BR>
Status: rascunho
Atualizado em: <YYYY-MM-DD>
Issue: #<N> (após `pnpm agent:register`; senão "—")
Priority: <P0 | P1 | P2 | P3>
Model: <slug model-selection>
Impeccable: <A | B | C | D> — <N/A sem UI | encaixe em tela X | fluxo novo em Y>
Appetite: <ex.: ~0,5–1 dia eng; um outcome verificável>
Responsável: —
## Intenção
<Por que isso existe agora. Problema ou oportunidade em prosa curta — voz do humano, não da stack.>
## Persona e fluxo
- **Persona / contexto:** <quem usa, onde (campo/mesa), estado de espírito>
- **Job principal:** <uma frase — o que precisa conseguir>
- **Fluxo desejado:** <passos em linguagem de usuário; o que vê / faz / decide>
- **Anti-goals de produto:** <o que esta entrega NÃO deve virar (ex.: spreadsheet mode, segundo cadastro de pessoa)>
### Esboço de fluxo (B/C/D)
<!-- ASCII de jornada, não layout de implementação. Omitir se A ou só controle isolado. -->
\```text
[início] → … → [outcome]
\```
## Objetivo e aceite
- <Outcome verificável em linguagem de produto, um por bullet>
- <Guardrails de produto que valem para o item: ex. "liderança não vê estimativas", "fail-closed se faltar consentimento" — sem nomear migration/collection>
## Dados (intenção)
<!-- Sempre presente. Sem métrica: "Dados: N/A — <por quê>". -->
- **Vou apresentar dados?** <Não | Sim, só aggregate para outro consumidor | Sim, superfície neste item>
- **Decisões desbloqueadas:** <ator + escolha; uma por bullet. Sem decisão nomeável → corte vaidade.>
- **Forma:** *adiada ao plano de implementação* — aqui só restrições de produto (ex.: "sem % estadual absoluto", "leitura relativa/local").
## Direção no codebase (hipótese)
<!-- Soft. Revisável. Sem signatures, sem "criar collection X", sem mermaid de solução. -->
- **Áreas prováveis:** <rotas `/campanha/…`, pastas `src/components/campaign/<domínio>/`, `src/utilities/<domínio>/`, `src/lib/…`>
- **Precedente a olhar:** <plano/Issue/arquivo análogo, se houver>
- **Risco de acoplamento:** <uma linha — o que o executor deve respeitar (ex.: leader lockdown, lista B18)>
## Dependências
- <IDs duros/suaves ou "Nenhuma">
## Fora de escopo
- <Exclusões de produto, com destino (outro ID/plano) quando houver>
## Rabbit holes de produto
- **<Risco>.** Se alguém “só completar”: <explosão de escopo>. **Corte neste item:** <…>.
## Questões em aberto (produto)
<!-- Opções + Recomendação de produto. Nunca pergunta sem posição. -->
- **<Pergunta>?** **Opções:** A | B | C. **Recomendação:** <…>. _(assumido — validar com produto)_ quando couber.
## Referências
- GitHub Issue #<N>
- <arquivos/rotas úteis para o executor abrir primeiro — como pista, não contrato>
- `AGENTS.md` / `docs/ARCHITECTURE.md` — só se o item toca convenção já travada no repo
````
Notas:
- Alvo: ~60–100 linhas. Mais que isso costuma significar engenharia vazando para a intenção.
- Classe **A:** `Impeccable: A — N/A`; omita esboço de fluxo.
- Não rode `/impeccable` aqui.
- Self-score shaping ≥4/5 antes de gravar.

View file

@ -1,209 +0,0 @@
# Template de plano (`docs/plans/<slug>.md`)
Estrutura extraída dos planos existentes (`overview-lista-nucleos.md`, `visitados-recentemente.md`, etc.). Manter as seções nesta ordem; omitir "Design (Impeccable)" apenas na classe **A** (só backend); **sempre** incluir "Dados → decisão → apresentação" (`N/A` se não houver superfície de dados); omitir a subseção "Referência visual (UX Pilot)" quando não houver design-ref; omitir "Wireframe (texto)" quando não houver layout a posicionar (ver skill `work-issue`).
Filtros de decisão (caro vs barato, appetite, rabbit holes, depth, fatias, doubt): [decision-quality.md](decision-quality.md).
Filtro de dados (apresentar? decisão? forma?): [data-presentation.md](data-presentation.md) — obrigatório se houver KPI/mapa/série/ranking; senão `Dados: N/A`.
Mapa skills de planejamento: [skills-map.md](skills-map.md).
````markdown
# <Título do item em pt-BR>
Status: rascunho
Atualizado em: <YYYY-MM-DD>
Issue: #<N> (preencher após `pnpm agent:register`; enquanto não registrado: "—")
Priority: <P0 | P1 | P2 | P3>
Model: <slug sugerido por model-selection: composer-2.5 | cursor-grok-4.5-low|medium|high | kimi-k3-low>
Impeccable: <A | B | C | D> — <uma linha: N/A sem UI | encaixe em tela X | UI nova em rota Y | ref Nome.png>
Appetite: <ex.: ~1–2 dias eng; migration + 1 action + encaixe em lista existente>
Responsável: —
## Premissas
<!-- Obrigatório. O que o plano assume e o gate deve confirmar. Não omita. -->
1. <premissa de produto / papel / schema / escopo>
2. <…>
→ Corrija no gate ou o implementador segue com estas.
## Design (Impeccable)
<!-- Obrigatório se Impeccable = B, C ou D. Omitir inteiro se A. -->
Âncoras: `PRODUCT.md` / `DESIGN.md` (register <product|brand>) · tema `data-theme='campaign'` (ou tokens do site público).
Na implementação (`work-issue`): <shape → craft → critique → polish | craft compacto → critique → polish | shape compacto (ref) → craft → …>. Declarar `harden`/`optimize` só se o Passo 8 do implement acionar gatilho (não pipeline fixo).
Brief compacto (obrigatório em C; se B ambíguo):
- **Persona / contexto:** <quem, onde, estado de espírito>
- **Job principal:** <uma frase>
- **Estratégia de cor:** Restrained (default) | <exceção justificada>
- **Edit where you see** (só `/campanha` staff, UI B/C/D): <sim — affordance no contexto + actions existentes | não — só leitura / `/editar` justificado> — princípio 3 de `PRODUCT.md`; rabbit hole: spreadsheet mode
- **Anti-goals:** <o que esta superfície não deve ser>
### Wireframe (texto)
<!-- Opcional no plano durável; obrigatório no plano de implementação (skill work-issue)
quando B/C/D posiciona blocos. Caixas ASCII + rótulos pt-BR; sem cores/pixels.
Omitir se só copy/controle isolado ou se "seguir design-ref à risca" sem adaptação. -->
\```text
┌─ <rota ou superfície> ───────────────────────────────┐
│ <bloco / região> │
│ <…> │
└──────────────────────────────────────────────────────┘
Fora do frame: <chrome compartilhado / tabs fora do item>.
\```
### Referência visual (UX Pilot)
<!-- Só se existir design em docs/design-refs/latest/. -->
Design: [`<Nome>.png`](../design-refs/latest/<Nome>.png) · [`<Nome>.html`](../design-refs/latest/<Nome>.html)
![<alt em pt-BR>](../design-refs/latest/<Nome>.png)
Como usar:
- **Adotar a estrutura:** <o que do design corresponde aos objetivos deste plano>.
- **Fora deste plano:** <partes do design que pertencem a outros planos, com links>.
- **Ajustar cores e código:** o HTML/PNG usa a paleta antiga (vermelho escuro `#8E0E23`, navy `#1B2B4B`, dourado `#C8874B`) e Tailwind via CDN. Implementar com os componentes shadcn existentes (`src/components/ui`) e os tokens do tema `data-theme='campaign'` (`src/app/(frontend)/styles.css`): fundo branco, primário `#C51414`, superfícies neutras claras.
<!-- Se o item nasce de critique: cite `.impeccable/critique/<snapshot>.md` aqui; não rode critique novo neste fluxo. -->
## Dados → decisão → apresentação
<!-- Obrigatório em todo plano (também na classe A). Sem métrica/mapa/série/ranking nesta entrega: uma linha "Dados: N/A — <por quê>". Caso contrário as três perguntas. Ver data-presentation.md. -->
- **Vou apresentar dados?** <Não (N/A) | Sim, só aggregate para &lt;consumidor&gt; | Sim, superfície neste item>
- **Decisões desbloqueadas:** <ator + escolha; uma por bullet. Sem decisão nomeável → corte vaidade.>
- **Forma escolhida:** <degrau da escada: número+contexto | tabela/lista | série | mapa | chart | …> — **por quê.** **Rejeitado:** <chart/mapa/KPI alternativos e por quê>.
- **Profile (se Sim):** tipo / granularidade / tamanho típico / absoluto vs relativo.
- **Anti-goals de dado:** <ex.: sem % estadual absoluto; sem gauge SaaS — ou "N/A">.
## Contexto
<Estado atual do sistema (com caminhos de arquivo reais), o problema/oportunidade, e a decisão
de produto que originou o item, com data. Responde "por que isso existe".>
## Objetivos (critérios de aceite)
<!-- Cada bullet = condição testável / verificável ao fim da Issue — não wish-list.
Incluir guardrails do item: access, migration sim/não, Consent, etc. -->
- [ ] <resultado verificável>
- [ ] <…>
- Guardrails: <access / migration / Consent / sem Neon / …>
## Boundaries (desta entrega)
<!-- Compacto. Defaults do repo não precisam de ensaio — só o que esta Issue reforça ou excepciona. -->
- **Always:** <ex.: queries com user + overrideAccess: false; pin unit do parser>
- **Ask first:** <ex.: collection nova; dependency nova; mudar URL pública>
- **Never:** <ex.: Consent por ID hardcoded; cadastro paralelo a Contact; tocar Neon>
## Decisões travadas
<!-- Só decisões caras de reverter. Formato: decisão + por quê + fonte/data + alternativas rejeitadas.
Ver decision-quality.md. Decisão silenciosa ou sem alternativas rejeitadas é defeito.
Decisão repo-wide além deste item → marcar "candidata a doc em docs/" (não criar ADR schema novo sem precedente). -->
- **<Decisão em negrito>.** <Racional e fonte com data.> **Rejeitado:** <alternativa A porque …; B porque …>.
- **i18n e naming** seguem o AGENTS.md: identificadores em inglês (<listar os principais
nomes propostos>), strings visíveis em pt-BR.
## Questões em aberto
<!-- Formato: Opções + Recomendação. Nunca pergunta sem posição. -->
- **<Pergunta>?** **Opções:** A | B | C. **Recomendação:** <posição concreta e por quê>. <"Definir com
produto" quando aplicável — mas nunca pergunta sem recomendação.>
## Abordagem proposta
\```mermaid
flowchart LR
<fluxo de dados/componentes da solução>
\```
Componentes:
<!-- Depth check: reusar módulos profundos existentes; não criar pass-through raso. -->
- **`<NomeDoComponente/função>`** (em `src/<caminho real>`): <responsabilidade, assinatura,
o que reusa. Queries Payload com `user` levam `overrideAccess: false`; escrita
multi-collection é transacional; hooks propagam `req`.>
- <um bullet por componente/arquivo novo ou alterado>
- **<Migration>**: <se houver: nome sugerido `pnpm migrate:create <nome>`, o que adiciona,
se tem backfill. Se não houver: "Sem migration, sem collection, sem server action.">
- **Docs de framework (se couber):** <API Payload/Next/WebAuthn a verificar na implementação contra a versão em package.json — não citar blog/SO.>
## Fases verificáveis
<!-- Fatias VERTICAIS (não "toda DB → toda API → toda UI"). Quota do appetite.
Fase 1 = tracer bullet. Cada fase: aceite + verify + files + tamanho S|M.
Se só 1 fase óbvia, uma entrada basta. L/XL → partir ou Issue bipartida. -->
### Fase 1 — Tracer: <título curto>
- **Quota:** <ex.: ~0,3d do appetite>
- **Entrega:** <path fino ponta a ponta que prova a aposta>
- **Aceite:**
- [ ] <condição testável>
- **Verify:** <pnpm gate:fast | pin unit/int path | check manual>
- **Files:** `src/…`, `tests/…`
- **Tamanho:** S | M
### Fase 2 — <título>
- **Quota:** …
- **Entrega:** …
- **Aceite:** …
- **Verify:** …
- **Files:** …
- **Tamanho:** S | M
### Checkpoint (se >2 fases)
- [ ] Aceites das fases 1–N verdes; sistema compilável; seguir ou cortar rabbit hole X.
## Dependências
- <Itens do roadmap dos quais depende (duras e suaves, identificadas) — ou "Nenhuma de
outro plano." + o que reusa do código existente, com caminhos.>
## Não escopo
- <Cada exclusão explícita, citando o plano/item do roadmap para onde ela vai.>
## Rabbit holes
<!-- Armadilhas de escopo se tocadas "de passagem" — distinto de Não escopo. -->
- **<Risco>.** Se alguém “só completar”: <explosão>. **Mitigação neste item:** <corte / boundary / defer+gatilho>.
## Adiado com gatilho
<!-- Opcional. Barato demais para o appetite agora, mas com evidência que reabre. -->
- **<O quê>.** Revisitar quando: <evidência concreta — ex. 3º call site, QPS, item B3 entregue>.
## Referências
- GitHub Issue #<N> (spec + frontmatter `id/depends/serializes/priority/model`)
- <arquivos-fonte reais que o implementador vai abrir, um por bullet, com o porquê>
- AGENTS.md — <quais convenções se aplicam: Campaign auth, naming, overrideAccess, etc.>
- <!-- Se B/C/D: --> `PRODUCT.md` / `DESIGN.md` — <o que deste item herda do Field Desk / register>
````
Notas:
- No bloco mermaid acima, remover as barras invertidas dos fences internos (`\``` → ` ``` `).
- Nível de detalhe alvo: ~100–160 linhas (Premissas + Fases acrescentam estrutura, não prosa). Menos que ~80 costuma significar que o Passo 3 (exploração do código) foi pulado.
- Classe **A**: omita a seção "Design (Impeccable)" e use no cabeçalho `Impeccable: A — N/A (sem superfície UI)`.
- Seção **Dados → decisão → apresentação** é sempre presente (preenchida ou `Dados: N/A`); não omita.
- Seções **Premissas**, **Objetivos (critérios de aceite)**, **Boundaries**, **Fases verificáveis** são sempre presentes. Chore trivial: Premissas 1 linha, Boundaries defaults, Fases = 1 entrada.
- Não rode `/impeccable craft|critique|polish` ao criar o plano — só classifique e semeie; a skill `work-issue` executa o ciclo.
- Self-score de qualidade de decisão (0–5) antes de gravar: ver [decision-quality.md](decision-quality.md). Se Dados ≠ N/A, self-check em [data-presentation.md](data-presentation.md) (≥3/5). Se Rabbit holes ou Adiado com gatilho estiverem vazios de propósito, escreva `Nenhum neste item.` — não omita a seção.

View file

@ -0,0 +1,56 @@
# Shaping de intenção (plan-issue)
Filtros para fatiar e descrever o que o humano quer — **sem** travar engenharia. Inspirado em Shape Up / 37signals (appetite, build less) e no caro-vs-barato de produto. Decisão silenciosa de produto é defeito; decisão silenciosa de schema aqui é **erro** (isso pertence ao plano de implementação).
## Fatia mínima útil
Cada Issue deve:
1. Caber num **appetite** declarado (tempo fixo, escopo flexível).
2. Entregar **um** outcome verificável sozinho.
3. Ser compreensível sem ler o epic-pai.
Se o pedido humano misturar jobs (ex.: “mapa + CSV + invite”), **separe** — a menos que um sem o outro não tenha valor.
| Preferir separar | Preferir manter junto |
| ---------------- | --------------------- |
| Outcomes distintos para personas distintas | Mesmo fluxo, mesma tela, mesmo aceite |
| Um pedaço desbloqueia o outro depois | Separar criaria handoff inútil |
| Um pedaço é jurídico/LGPD e o outro não | — |
## Appetite
Declare quanto o slice vale, não estimativa aberta:
- Exemplos: `~0,5 dia, só copy/fluxo` · `~1 dia, um encaixe em lista existente` · `~1–2 dias, fluxo novo numa rota`
- Se a intenção não cabe → cortar rabbit holes / Fora de escopo, **não** inflar o item nem detalhar engenharia para “caber”.
## Caro de reverter (produto) vs barato
No plano de intenção, “travar” só o que é caro **de produto** e já é política do repo ou decisão humana explícita:
| Pode afirmar na intenção | Deixar para o plano de implementação |
| ------------------------ | ------------------------------------ |
| Leader lockdown / assimetria de votos | Collection nova, unicidade, shape do schema |
| Fail-closed de consentimento (conceito) | Chave `Consent` concreta, textos versionados |
| “Sem % estadual absoluto” | Chart vs tabela vs mapa |
| Appetite e fora de escopo | Nomes de utilities, signatures, migration |
## Rabbit holes de produto
Armadilhas se alguém “só completar” o desejo humano:
- Segundo cadastro de pessoa paralelo a `Contact`
- Spreadsheet mode / edição em massa sem pedido
- Dashboard de vaidade sem decisão nomeável
- Escopo que puxa redesign de paleta ou shell inteiro
## Self-score (0–5, gate ≥4)
1. Fatia = um outcome verificável?
2. Appetite declarado e a intenção cabe nele?
3. Persona + job + aceite claros (sem jargão de stack)?
4. Direção no codebase é hipótese (não contrato técnico)?
5. Zero decisões duras de engenharia no plano?
&lt;4 → corrigir antes de gravar / registrar Issue.

View file

@ -203,6 +203,7 @@ Opcional e leve (se o rebase tocou schema/types): `pnpm exec tsc --noEmit` nos a
## Posição no fluxo
```
plan-issue → work-issue (claim → execução → /simplify+/impeccable
→ rebase-on-main → capture-review-debts → PR --base stage → merge)
plan-issue → work-issue | agent-work-issue
(impl plan → execução → /simplify → rebase-on-main?
→ capture-review-debts → PR --base main → merge)
```

View file

@ -1,159 +1,80 @@
---
name: work-issue
description: Conduz uma GitHub Issue rastreável do Teqo do claim ao merge em main — prep (pnpm i), claim (pnpm agent:claim), renomear a sessão + abrir o plano no editor, verificação do modelo declarado na Issue, freshness audit do plano, execução das fases (schema/server → UI via /impeccable → gates), /simplify (3 reviewers paralelos via Task) + capture-review-debts, PR --base main 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").
description: >-
Versão humana de agent-work-issue: claim de uma Issue, Plan mode com plano
de implementação deliberado a partir da intenção, pausa para confirmação
humana, depois execução → /simplify → capture-review-debts → PR Ready em
main com auto-merge. Use quando o usuário pedir /work-issue, quiser
supervisionar a abordagem de engenharia, ou trabalhar uma Issue com gate
humano antes do código.
disable-model-invocation: true
---
# Trabalhar uma Issue (claim → merge em main)
# Work-issue (humano supervisiona)
Esta skill conduz UMA Issue rastreável do claim ao merge em `main`. 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).
Mesmo pipeline de [`agent-work-issue`](../agent-work-issue/SKILL.md), com duas diferenças:
**Proibido neste fluxo:** qualquer acesso a DB de prod, merge sem CI green, editar outras Issues `in-progress`.
1. **Você claima** a Issue (`pnpm agent:claim`).
2. **Pausa após o plano de implementação** até o humano confirmar — só então executa.
**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.
**Proibido:** DB de prod; merge sem CI green; editar outras Issues `in-progress`; pular a pausa do impl plan; Draft / sem auto-merge.
## Checklist do fluxo
## Checklist
```
- [ ] 0. Prep: `pnpm i` antes do `agent:claim` (Cloud Agents já rodam via `.cursor/environment.json` → `install`; worktrees locais: obrigatório, ou deixe para o `ensure-repo-deps` do `pnpm push`). Cloud → §Prep Cloud (sem Docker; não use `db:start`)
- [ ] 1. Claim: pnpm agent:claim (ou -- --issue <N>) — o brief do stdout é o contrato
- [ ] 1b. Renomear a sessão (cursor-app-control rename_chat) — padrão `#<N> <id> — <título>` (linha `rename_chat:` do brief)
- [ ] 1c. Abrir o plano no editor (cursor-app-control open_resource) para o humano acompanhar
- [ ] 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 main: branch → commit → **`pnpm push -u origin HEAD`** (não `git push` nu) → gh pr create --base main (Closes #N, sem --draft)
→ gh pr merge --auto --merge → gh pr checks --watch --required até o merge → consolidar pontas soltas
- [ ] 0. Prep: `pnpm i` se preciso
- [ ] 1. Claim: pnpm agent:claim (ou -- --issue <N>)
- [ ] 1b. rename_chat + open_resource (intenção)
- [ ] 2. Verificação de modelo (assimétrica — pausa se sessão mais forte)
- [ ] 3. Plan mode → escrever `*-impl.md` → **PARAR e confirmar com o humano**
- [ ] 4. Após “ok”: executar como agent-work-issue Passos 4–6
```
## Passo 0 — Prep (deps)
`pnpm agent:claim` depende de `node_modules` (scripts em `scripts/` importam pacotes do projeto). Em worktree/clone fresco, ou quando `node_modules` não existir, rode **antes** do claim:
## Passo 0–1 — Prep e claim
```bash
pnpm i
pnpm agent:claim # topo da fila
pnpm agent:claim -- --issue <N>
```
Não pule este passo — sem deps instaladas o claim falha antes de imprimir o brief.
O brief do stdout é o contrato de **produto** (id, prio, model, link da intenção). Claim = `ready → in-progress`.
### Prep Cursor Cloud (sem Docker)
### Rename + abrir intenção
VMs Cloud **não têm Docker** — `pnpm db:start` (docker compose) **não funciona** aqui. O ambiente já sobe Postgres nativo via `.cursor/environment.json` (`cloud-setup.sh` no install + `ensure-postgres.sh` no start): bancos `teqo` e `teqo_test` migrados e com `db:seed:minimal`.
Padrão: `#<N> <id> — <título>` via `cursor-app-control` `rename_chat`.
Abra o plano de intenção com `open_resource` (`file:///…/docs/plans/<slug>.md`).
- **`pnpm gate:fast` e `pnpm gate:push` não precisam de Postgres** — `test:unit` usa `DATABASE_URL` inválida de propósito (sem conexão real).
- Só `pnpm test:int` / `pnpm migrate` tocam o banco — já preparado no install; se conexão falhar: `bash ./.cursor/ensure-postgres.sh`.
- **Proibido `git push --no-verify`** no fechamento da Issue. O pre-push roda `pnpm gate:push` (~1–2 min) — espere passar; CI não substitui o hook local.
## Passo 2 — Modelo
## Passo 1 — Claim
Regra assimétrica (`model-selection`):
```bash
pnpm agent:claim # pega o topo da fila (ready, desbloqueadas, por prio)
pnpm agent:claim -- --issue <N> # quando o usuário especifica
```
- Sessão **mais fraca** que `model:` → informa e segue
- Sessão **mais forte** → **informa e pausa** (“pedir X, está em Y — seguir?”)
- Ausente → aplique model-selection e registre na Issue
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 3 — Plano de implementação + GATE humano
### Renomear a sessão
Siga o **Passo 3** de `agent-work-issue` (Plan mode, engineering-brief, decision-quality, `docs/plans/<slug>-impl.md`).
Logo após o claim bem-sucedido, **renomeie a aba desta conversa** para o humano identificar o trabalho em curso — não espere ele pedir. Política do repo: no fluxo `work-issue` isso **não** é opcional — a descrição padrão da ferramenta MCP ("só quando o usuário pedir") não se aplica aqui.
Depois de gravar o impl plan:
**Padrão canônico** (decisão travada — use sempre este formato, sem variações):
1. Apresente no chat: abordagem recomendada, opções rejeitadas, fases, riscos, o que diverge da hipótese de direção da intenção.
2. **Pare.** Não escreva código de feature até confirmação explícita (“ok”, “pode executar”, “aprovado”, …).
3. Se o humano pedir mudança de abordagem → revise o `*-impl.md` e reapresente.
4. Confirmação → marque Status `aprovado` no impl plan → `SwitchMode` `agent` → continue.
| Campo | Fonte no brief | Regra |
| ----- | --------------- | ----- |
| `#<N>` | linha `Claimed #<N> — …` | número GitHub da Issue; sempre presente |
| `<id>` | linha `id: …` | id de roadmap (`B79`, `C11`, `FD2+`…); omita o segmento se `(none)` |
| `<título>` | título da Issue (após `Claimed #<N> — `) | se começar com `<id> — `, remova esse prefixo para não duplicar |
## Passos 4–6 — Execução
**Montagem:**
Idênticos a `agent-work-issue`:
- Com `id`: `#<N> <id> — <título>` — ex.: `#456 B79 — Mapa LQ na legenda`
- Sem `id`: `#<N> — <título>` — ex.: `#789 — Hotfix cookie path`
- Executar fases (schema/server → UI → gates)
- `/simplify` completo + fixes
- `capture-review-debts` **com** gate humano (Passo 5 daquela skill) — não use o modo autônomo do pool
- `pnpm push` → PR Ready `--base main` + `Closes #N` → auto-merge → `gh pr checks --watch --required`
**Truncagem:** limite da ferramenta = 200 caracteres. Preserve intactos `#<N>` e `<id>`; encurte só o `<título>` no final (reticências opcionais).
Detalhes, Prep Cloud, invariantes e templates: leia [`agent-work-issue/SKILL.md`](../agent-work-issue/SKILL.md) e os arquivos em `.cursor/skills/work-issue/` (`engineering-brief.md`, `implementation-template.md`, `decision-quality.md`).
**Passos:**
## Resumo final
1. Monte o título pelo padrão acima a partir do stdout do claim.
2. Chame `cursor-app-control` → `rename_chat` com `title`.
3. Se `rename_chat` não estiver disponível (fora da Agents Window), informe em uma linha o título exato sugerido para o humano renomear manualmente — mas tente o MCP primeiro.
Se a sessão continuar uma Issue já claimada (sem re-rodar claim), derive os mesmos campos do brief anterior na conversa ou de `gh issue view <N> --json number,title` + frontmatter `id:`.
### Abrir o plano para o humano
Em seguida, **abra o arquivo do plano no editor** para quem acompanha a sessão — não basta `Read` no chat.
1. Extraia o caminho do plano do brief (`docs/plans/<slug>.md`) ou do link `Plano:` no body da Issue.
2. Chame `cursor-app-control` → `open_resource` com URI absoluta, ex.: `file:///…/docs/plans/foo.md` (caminho relativo resolvido a partir da raiz do workspace).
3. Informe em uma linha qual plano foi aberto (`B79 — docs/plans/…`).
Se `open_resource` não estiver disponível (fora da Agents Window), diga o caminho absoluto do plano para o humano abrir manualmente — mas tente o MCP primeiro.
## 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` (Composer 2.5 ↔ Grok 4.5 ↔ Kimi K3 Low). 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:`).
- Issue `{id}-exec` / `kimi-k3-low` sem a dep de plan `done` → **pare** (não execute sem plano fechado).
Subagentes despachados via `Task` saem **no modelo da propriedade** quando couber (`Task.model` ∈ `composer-2.5` | `cursor-grok-4.5-high` | `kimi-k3-low`; se a Issue for `-low`/`-medium` e o enum não listar, `inherit` — ver model-selection).
## 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** — iteração: `pnpm gate:fast`. Push: **`pnpm push -u origin HEAD`** (ensure-deps + `gate:push` no script — não depende do hook Husky). `pnpm gate:push` manual só para debug sem push. Scan Aikido dos arquivos editados. Comandos bare, nunca piped. **Nunca** `git push --no-verify` cru (pula o gate) — em Cloud não há Docker, mas `gate:fast`/`gate:push` não precisam de banco (ver §Prep Cloud).
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 **antes** do Passo 6. Não pule os reviewers — o simplify deste fluxo é o comando completo, não uma leitura manual do diff.
### Escopo
1. `git diff --no-color` + `git diff --cached --no-color` (diff combinado da sessão).
2. Se vazio, arquivos/símbolos citados na conversa; se ainda vazio, `git show --stat --patch --no-color HEAD`.
### Reviewers paralelos (obrigatório)
Lance **três** subagentes via `Task` **em paralelo** na mesma mensagem — read-only, mesmo modelo da sessão, **sem editar arquivos**. Passe o diff combinado (ou lista de arquivos + hunks relevantes se o diff for grande):
1. **Code quality** — comentários vazios, helpers de uso único, nullable desnecessário, try/catch amplos, abstração prematura, casts fracos, estado derivado duplicado, código morto.
2. **Performance** — I/O bloqueante em hot path, recomputação sem cache, busy-wait, concatenação em loop, N+1, logging em loop.
3. **Reuse** — padrões/helpers existentes no repo ou já presentes no diff que o escopo deveria reutilizar.
### Fixes + débitos
1. Agregue os achados dos três reviewers e aplique **fixes pontuais** no diff (comportamento preservado).
2. Achados maiores que o cleanup da sessão → skill `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>]`).
3. Resuma o que corrigiu e o que ficou como recomendação/débito.
## Passo 6 — Fechar em main
1. Branch `agent/<id>-<slug>` (worktrees do Cursor são donos da criação; commits lógicos).
2. **`pnpm push -u origin HEAD`** — canonical; roda `ensure-repo-deps` + `gate:push` + push (não depende do Husky). Não use `git push` nu.
3. Abrir PR **Ready** (nunca draft) com `Closes #<N>` — `.cursor/rules/agent-pr-workflow.mdc` (alwaysApply). Canal: `gh pr create --base main` **ou**, em Cloud, `ManagePullRequest` com **`draft: false`**.
4. `gh pr merge --auto --merge <PR>` **imediatamente** após o PR existir Ready (`strict=false` na proteção de `main`). Não encerre o turn com PR Draft ou sem auto-merge armado.
5. **Acompanhe só os checks obrigatórios** (`gh pr checks <PR> --watch --required`): gate = `checks` + `migration-lock`; Vercel Git não bloqueia. Falha no ci-pr → corrige na mesma branch. **Conflito de merge** → rebase em `main` e reempurre.
6. O flip `in-progress → done` + `in-prod` é **determinístico no CI** (`issue-done-on-main-merge.yml`). Deploy gated fica em `ci.yml` — não é passo do agente. Consolide pontas soltas após o merge.
## Resumo final ao usuário
Issue trabalhada + sessão renomeada + plano aberto no editor + 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 (3 reviewers paralelos) + débitos registrados, gates (`pnpm push`, sem `--no-verify` cru), link do PR e estado do merge em main, pontas soltas consolidadas. `done`+`in-prod` no merge; deploy gated em `ci.yml`.
Issue claimada · sessão renomeada · intenção aberta · modelo · **impl plan confirmado pelo humano** · execução · simplify/débitos · PR + merge.

View file

@ -0,0 +1,51 @@
# Qualidade de decisão (plano de implementação)
Aplique ao escrever `docs/plans/<slug>-impl.md` em `work-issue` / `agent-work-issue`. O plano de **intenção** já fixou o outcome — aqui se escolhe a engenharia. Decisão silenciosa é defeito.
## Caro vs barato
Delibere e registre só o **caro de reverter**. O barato vira Não escopo, fill-in, ou “mais simples que funciona” com **gatilho de revisitação**.
| Caro (decidir agora + rejeitadas) | Barato (adiar / mais simples) |
| --------------------------------- | ----------------------------- |
| Collection nova, unicidade, access | Polish cosmético, 2º estilo de card |
| Nova chave `Consent` / PII | Copy, motion, a11y P3 |
| Semântica multi-collection / locks | Prefetch, ordem de colunas |
| URL pública / slug imutável | Rename de pureza |
| Fronteira de módulo em volatilidade real | Adapter com 1 call site |
## Forma obrigatória
Toda decisão não trivial de engenharia:
```text
Opções: A | B | C
Recomendação: B — porque …
Alternativas rejeitadas: A porque …; C porque …
```
No `*-impl.md`: **Decisões de engenharia** = decisão + por quê + rejeitadas.
## Appetite e tracer bullet
Respeite o appetite do plano de intenção. Se a abordagem estoura → cortar rabbit holes, não inflar. Preferir **tracer bullet** cedo (schema mínimo → uma action → uma superfície) antes de polish paralelo.
## Depth check
Antes de propor arquivo/utility/componente novo:
1. Já existe módulo profundo? (`campaignAccess`, shells de lista, `withPayloadTransaction`, …) → **reusar**
2. Pass-through raso? → **não criar**
3. Conhecimento vazaria em N módulos? → **encapsular uma vez**
## Rabbit holes Teqo
Layers/cerimônia sem volatilidade; cadastro paralelo a `Contact`; Consent por ID hardcoded; DRY &lt;3 call sites; redesign de paleta fora de `campaign`.
## Self-score (0–5, gate ≥4)
1. Decisões caras têm rejeitadas?
2. Abordagem cabe no appetite da intenção?
3. Rabbit holes nomeados?
4. Depth check: reusa shells/helpers existentes?
5. Intenção (aceite de produto) permanece satisfeita — engenharia não reescreveu o outcome?

View file

@ -0,0 +1,36 @@
# Brief de engenharia (carregar antes do plano de implementação)
Leia o que for relevante **antes** de travar a abordagem no `*-impl.md`. Não invoque jornadas inteiras de skills — aplique o princípio no momento da decisão.
## Pinos do repo (sempre)
- `.cursor/rules/codebase-map.mdc` — direção `lib/` → `utilities/` → `components/` → `app/`; dono da feature
- `.cursor/rules/engineering-standards.mdc` — gates, type honesty, client boundary, caching ladder, access
- `.cursor/rules/security-critical.mdc` — quando tocar access/Local API/overrideAccess
- `AGENTS.md` — auth campanha, Consent fail-closed, transactions, naming, DB local
- `docs/ARCHITECTURE.md` — se a mudança cruza verticais ou modelo de domínio
## Skills sob demanda (não tour)
| Situação | Skill / princípio |
| -------- | ----------------- |
| Onde colocar lógica / dependência | `clean-architecture` — Dependency Rule; core testável |
| Complexidade de módulo / API | `software-design-philosophy` — deep modules, anti-classitis |
| Escopo v1 / cortar especulação | `37signals-way` / `pragmatic-programmer` — build less, tracer bullet, DRY de conhecimento |
| Schema Payload | skill `payload-migrations` |
| DB local / Cloud sem Docker | skill `local-database` |
| KPI/mapa/série na UI | [data-presentation.md](../plan-issue/data-presentation.md) pergunta 3 no impl |
| Domínio `/campanha` específico | rules `projects/*` se o item tocar aquele projeto |
## Invariantes que o impl plan não pode violar
- Local API com `user` → `overrideAccess: false`
- Escrita multi-collection → transação + `req: { transactionID }`
- Pessoa → join com `Contact` (não collection paralela)
- Opt-in/PII → `Consent` por chave estável, fail-closed
- `leader` lockdown; sem `estimatedVotes` para liderança
- Copy pt-BR / identificadores em inglês
## Sistema de listas
Se a superfície for lista/tabela: reusar shells (`CampaignTable`, URL canônica, column visibility, pending boundary) — ver codebase-map. Não reinventar.

View file

@ -0,0 +1,65 @@
# Template de plano de implementação (`docs/plans/<slug>-impl.md`)
Criado em Plan mode por `work-issue` / `agent-work-issue` a partir do plano de **intenção**. Aqui a engenharia é deliberada — Opções + Recomendação + rejeitadas ([decision-quality.md](decision-quality.md)).
O outcome de produto do plano de intenção é **inviolável**. A forma técnica é **livre** desde que mantenha aceite, appetite e invariantes do repo ([engineering-brief.md](engineering-brief.md)).
````markdown
# Impl: <mesmo título da intenção>
Status: rascunho | aprovado | em execução
Atualizado em: <YYYY-MM-DD>
Issue: #<N>
Intenção: docs/plans/<slug>.md
Appetite restante: <herdado / ajustado com corte explícito>
## Leitura da intenção
- **Outcome:** <1–2 frases, nas palavras do aceite de produto>
- **O que NÃO negociar:** <lockdowns de produto / access / LGPD citados na intenção>
- **O que reavaliar:** <hipóteses de “Direção no codebase” que podem estar erradas>
## Abordagem recomendada
\```mermaid
flowchart LR
…
\```
**Opções consideradas:** A | B | C
**Recomendação:** <…> — porque …
**Rejeitadas:** …
### Componentes / mudanças
- **`<símbolo>`** (`src/…`): <responsabilidade; o que reusa>
- **Migration:** <nome sugerido / “sem migration”>
- **Access / Consent:** <helpers; chave se houver; fail-closed>
- **UI:** <Impeccable A–D; shells a reusar; shape→craft→critique→polish se B/C/D>
### Dados → forma (se aplicável)
- Forma escolhida + por quê + rejeitadas (pergunta 3 de data-presentation)
## Fases verificáveis
1. **Tracer / schema+server** — <quota do appetite>
2. **UI** — <…>
3. **Gates** — `pnpm gate:fast`; push via `pnpm push`
## Rabbit holes / Não escopo (engenharia)
- …
## Riscos e mitigação
- …
## Aceite de engenharia
- [ ] Aceite de produto da intenção ainda coberto
- [ ] Invariantes AGENTS/engineering-standards
- [ ] Testes de domínio previstos (unit/int) onde access/write paths mudam
````
Self-score decision-quality ≥4 antes de marcar `aprovado` ou executar.

View file

@ -18,7 +18,7 @@ claim → feature branch → PR --base main → CI PR green (cascade + skips)
main → ci.yml full suite → vercel deploy --prod (se verde) → requeue se HEAD andou
```
**Skills:** `plan-issue` → `work-issue` (claim → modelo → freshness → execução → /simplify → PR `--base main` → CI até o merge) → `project-status`. `docs/roadmap.md` = legado congelado; fonte canônica = GitHub Issues.
**Skills:** `plan-issue` (intenção + Issues) → `work-issue` (humano: claim → impl plan → confirmação → execução) ou `agent-work-issue` (pool: já claimada → impl plan → execução sem pausa) → `/simplify` → `capture-review-debts` → PR `--base main` → `project-status`. `docs/roadmap.md` = legado congelado; fonte canônica = GitHub Issues.
- **Agente faz sozinho:** `pnpm agent:claim` → implementa → **`pnpm push`** → PR **Ready** (nunca draft) com `Closes #N` → `gh pr merge --auto --merge` → `gh pr checks --watch --required`. Regra always-on: `.cursor/rules/agent-pr-workflow.mdc`. Em Cursor Cloud: `ManagePullRequest` com `draft: false`, depois armar auto-merge via `gh pr merge --auto --merge` (o default draft da tool **não** vale neste repo).
- **Só humano:** secrets Vercel (`VERCEL_TOKEN`, `VERCEL_ORG_ID`, `VERCEL_PROJECT_ID`), `POOL_GITHUB_TOKEN`, `pnpm configure:branch-protection`, editar envs Neon/Vercel.

View file

@ -4,6 +4,8 @@ Conteúdo movido do `AGENTS.md` em 2026-07-30 (fatiamento do paradigma de agente
---
**Recently resolved (2026-08-02):** **Skills plan/work reescritas** — `plan-issue` agora só gera planos de **intenção** (persona/fluxo/aceite + direção suave no código; sem decisões duras de engenharia). Execução: `agent-work-issue` (pool — Plan mode → `*-impl.md` → executa → `/simplify` → `capture-review-debts` autônomo → PR Ready + auto-merge) e `work-issue` (humano — claim + **pausa** após o impl plan). Prompt do pool aponta para `agent-work-issue`.
**Recently resolved (2026-08-02):** **WhatsApp interno D3–D5 descartado** — Issues #30–#32 `wontfix` (bridge Baileys/Evolution/WAHA / linked device): risco de ban do número pessoal do staff. Canal no produto = só `wa.me`. Planos `whatsapp-interno-campanha.md`, `whatsapp-canal-fundacao.md`, `whatsapp-envio-liderancas.md`, `whatsapp-sugestao-atualizacoes.md` removidos; refs em `notifications.md` / convite·email listas / fluxos-ação / regra `nucleos-eleitorais` atualizadas.
**Recently resolved (2026-08-02):** **Agent pool hard max → 12** — `POOL_HARD_MAX_SLOTS` de 8 → 12 (`scripts/lib/agent-pool-state.mjs`); default continua 5. Skill `agent-pool` alinhada.

View file

@ -3,7 +3,7 @@
* (docs/plans/agent-pool-orchestrator.md).
*
* The pool keeps up to POOL_MAX_SLOTS (default 5) Cursor Cloud Agents running
* work-issue over `ready` autonomous-eligible issues. The supervisor is
* agent-work-issue over `ready` autonomous-eligible issues. The supervisor is
* REMOTE: a stateless GitHub Actions tick (`.github/workflows/agent-pool.yml`)
* runs `workflow --action …` / `tick --live`; humans drive it via
* `gh workflow run` (canonical channel). Local usage is inspection +

View file

@ -3,10 +3,9 @@
* (docs/plans/agent-pool-orchestrator.md §4/§5).
*
* The supervisor claims the issue BEFORE spawning (label flip + pool-worker
* marker comment — the coordinated-claim anti-race), so the worker SKIPS the
* claim step of work-issue and starts at step 1b. Everything else — gates, PR
* base main with Closes #N, auto-merge + CI watch — is the standard skill
* contract restated so the worker cannot miss it.
* marker comment — the coordinated-claim anti-race), so the worker SKIPS
* claim and runs `agent-work-issue` (autonomous: impl plan → execute →
* simplify → capture-review-debts → PR). Human-supervised path is `work-issue`.
*/
/** First docs/plans/*.md path in the issue body (the linked plan), if any. */
@ -31,22 +30,24 @@ export const buildPoolWorkerPrompt = ({ issueNumber, issueTitle, issueId, planPa
'',
'## Fluxo',
'',
'Siga a skill `.cursor/skills/work-issue/SKILL.md` a partir do passo 1b, PULANDO o passo 1 (claim):',
'Siga a skill `.cursor/skills/agent-work-issue/SKILL.md` por completo (Issue já claimada):',
'1. Rode `pnpm i` se `node_modules` não existir.',
planPath
? `2. Plano: \`${planPath}\` — freshness audit enxuto (passo 3 da skill).`
: '2. O body da Issue é a spec (não há plano linkado — avalie se ele basta para trabalhar).',
'3. Execute as fases com os gates do repo: `pnpm gate:fast` antes do push (o pre-push roda `pnpm gate:push`). Comandos bare, nunca piped.',
`4. PR obrigatoriamente com \`gh pr create --base main\` e "Closes #${issueNumber}" no body.`,
'5. `gh pr merge --auto --merge <PR>` e acompanhe `gh pr checks <PR> --watch --required` até o merge. Falha de CI no seu PR é sua (docs/AGENT-OPS.md — "Dono do PR, dono do CI"): corrija na mesma branch.',
? `2. Plano de intenção: \`${planPath}\` — abra-o; depois Plan mode e escreva \`docs/plans/<slug>-impl.md\` (engenharia deliberada; pode divergir da hipótese de direção se o aceite de produto se mantiver).`
: '2. O body da Issue é a spec de intenção (não há plano linkado). Em Plan mode, escreva mesmo assim um `docs/plans/<id>-impl.md` a partir do body.',
'3. Execute o impl plan. Gates: `pnpm gate:fast` na iteração; entrega com `pnpm push` (não `git push` nu). Comandos bare, nunca piped.',
'4. Rode `/simplify` completo; `capture-review-debts` em modo autônomo (só expensive_lock ≥4).',
`5. PR obrigatoriamente com \`gh pr create --base main\` e "Closes #${issueNumber}" no body (Ready, nunca draft).`,
'6. `gh pr merge --auto --merge <PR>` e acompanhe `gh pr checks <PR> --watch --required` até o merge. Falha de CI no seu PR é sua (docs/AGENT-OPS.md — "Dono do PR, dono do CI"): corrija na mesma branch.',
'',
'## Proibido',
'',
'- `DATABASE_URL` de prod ou `ALLOW_REMOTE_DB` — o setup local (`.cursor/cloud-setup.sh` + seed mínimo) cobre tudo.',
`- Editar outras Issues \`in-progress\` ou trabalhar fora da Issue #${issueNumber}.`,
'- Tratar o plano de intenção como contrato de engenharia — ele é intenção; o `*-impl.md` é a engenharia.',
'',
modelSlug
? `Modelo declarado da Issue: \`${modelSlug}\` — você foi spawnado nele (ou no fallback documentado pelo pool); a verificação assimétrica do passo 2 não se aplica.`
? `Modelo declarado da Issue: \`${modelSlug}\` — você foi spawnado nele (ou no fallback documentado pelo pool); a verificação assimétrica de work-issue não se aplica.`
: 'A Issue não declara `model:` — você foi spawnado no default do pool (composer-2.5).',
'',
`Ao terminar — merge concluído ou falha terminal — comente na Issue #${issueNumber} o desfecho em uma linha e encerre.`,

View file

@ -16,10 +16,11 @@ const campaignFixtures = installCampaignFixtures({
},
})
/** Counts pool statements matching `fragment` while `run` executes. */
/** Counts pool statements matching `fragment` (or `match`) while `run` executes. */
const countStatements = async <T>(
fragment: string,
run: () => Promise<T>,
match?: (text: string, params: unknown) => boolean,
): Promise<{ result: T; count: number }> => {
const pool = (payload.db as unknown as { pool: { query: (...args: unknown[]) => unknown } }).pool
const originalQuery = pool.query.bind(pool)
@ -33,7 +34,10 @@ const countStatements = async <T>(
: typeof (first as { text?: unknown })?.text === 'string'
? ((first as { text: string }).text as string)
: ''
if (text.includes(fragment)) count += 1
const params =
typeof first === 'string' ? args[1] : ((first as { values?: unknown })?.values ?? args[1])
const hits = match ? match(text, params) : text.includes(fragment)
if (hits) count += 1
return originalQuery(...args)
}
@ -67,29 +71,41 @@ describe('access-control per-request memo', () => {
const fixtures = campaignFixtures()
const coordinator = await fixtures.createCampaignUser('coordinator')
const municipality = await fixtures.getMunicipality()
const leadershipIds: number[] = []
for (let index = 0; index < 3; index += 1) {
const contact = await fixtures.createContact()
await fixtures.createLeadership({
const leadership = await fixtures.createLeadership({
contact: contact.id,
municipalities: [municipality.id],
supportStatus: 'engajado',
})
leadershipIds.push(leadership.id)
}
const { result, count } = await countStatements('from "campaign_user"', () =>
payload.find({
collection: 'leadership',
// depth 1 is what the list loaders use; it is also what multiplies the
// field-level access checks across every populated relation.
depth: 1,
limit: 25,
user: coordinator,
overrideAccess: false,
}),
// Count only SELECT … WHERE id = <actor>. Other `campaign_user` rows can
// appear at depth 1 when leftover docs in the same municipality have
// `user` set — that is populate, not a broken memo.
const { result, count } = await countStatements(
`from "campaign_user"`,
() =>
payload.find({
collection: 'leadership',
// depth 1 is what the list loaders use; it is also what multiplies the
// field-level access checks across every populated relation.
depth: 1,
limit: 25,
user: coordinator,
overrideAccess: false,
where: { id: { in: leadershipIds } },
}),
(text, params) =>
text.includes('from "campaign_user"') &&
Array.isArray(params) &&
params.includes(coordinator.id),
)
expect(result.docs.length).toBeGreaterThan(0)
expect(result.docs).toHaveLength(3)
// One read for the whole operation. Before the fix this was in the hundreds
// and grew with rows × populated fields.
expect(count).toBe(1)

View file

@ -19,6 +19,12 @@ describe('buildPoolWorkerPrompt', () => {
expect(prompt).toContain('in-progress')
})
it('points workers at agent-work-issue and forbids treating intention as engineering contract', () => {
expect(prompt).toContain('agent-work-issue/SKILL.md')
expect(prompt).toContain('*-impl.md')
expect(prompt).toContain('plano de intenção como contrato de engenharia')
})
it('pins the PR contract: base main, Closes #N, auto-merge, CI watch', () => {
expect(prompt).toContain('gh pr create --base main')
expect(prompt).toContain('Closes #42')