feat(OPS113): designer e designer-degraded — design hi-fi como fonte de verdade do port (Closes #1056)

This commit is contained in:
Francisco Solla 2026-09-15 23:42:23 -03:00
parent 488d7af7bb
commit 6769ca2e9a
6 changed files with 298 additions and 26 deletions

View file

@ -1,63 +1,100 @@
# Rascunho UI/UX do gate (plan-issue)
# Design hi-fi do gate (plan-issue)
Quando o item **muda UI** (classe Impeccable **B / C / D**, ou qualquer superfície que o usuário vê/toca), o gate **obrigatoriamente** apresenta um **rascunho visual** da intenção — não ASCII sozinho, não wireframe de implementação. O meio é **HTML + Tailwind**, commitado no repo Teqo junto do plano.
Quando o item **muda UI** (classe Impeccable **B / C / D**, ou qualquer superfície que o usuário vê/toca), o gate **obrigatoriamente** apresenta o **design hi-fi** da intenção — não ASCII sozinho, não wireframe de implementação. O meio é **HTML + Tailwind** com **tokens reais, brand e shadcn**, commitado no repo Teqo junto do plano. O artefato é a **fonte de verdade do port**: quem implementa (`work-issue` / `agent-work-issue`) porta **classe-a-classe** para React/Next.
## Para que serve — e para que NÃO serve
Serve para **colaborar visualmente com o humano** e fechar **layout, espaçamentos e tamanhos**: hierarquia, zonas, CTAs, densidade, medidas reais. É a linguagem do gate para "é isso que o usuário vê/toca".
Serve para **aprovar o design final antes de qualquer código** e, depois, **portar e criticar com paridade**: layout, espaçamentos, tamanhos, hierarquia, estados, tokens, copy. É a linguagem do gate para "é isso que o usuário vê/toca".
**NÃO é** implementação da feature, **NÃO é** protótipo funcional, **NÃO é** entrega de app, **NÃO é** decisão de engenharia. Quem executa (`work-issue` / `agent-work-issue`) constrói a partir do plano; o rascunho é descartável como fonte e imutável como registro.
**NÃO é** implementação da feature, **NÃO é** protótipo funcional, **NÃO é** entrega de app, **NÃO é** decisão de engenharia. Não há lógica de negócio, dados reais, chamadas de rede ou persistência.
## O que o rascunho DEVE ter (fidelidade mínima)
- **Imutável como registro:** o design aprovado viaja com a Issue e fica no repo; planos antigos (`docs/plans/**`) não se migram.
- **Mutável durante o work-issue:** o `designer` pode estender/ajustar o artefato na execução; **mudança material volta ao humano no PR** — nunca em silêncio.
## Quem produz e quem critica
Mesma doutrina para os dois papéis (fonte única — os prompts dos agentes apontam para cá, não copiam as regras):
- **Criar:** o agente `designer` (`.opencode/agent/designer.md`) produz ou estende o hi-fi a partir do plano de intenção aprovado — tokens/brand reais, copy pt-BR real, cenas 390/1280, estados críticos. O artefato nasce **antes** da implementação e é o alvo do gate.
- **Criticar:** o `designer` relê a **implementação renderizada** (screenshots do app) contra o artefato aprovado e devolve **lista numerada de ajustes concretos** — hierarquia (o CTA primário domina?), contraste, tipografia, espaçamento, mobile, acessibilidade. **A referência é o alvo — nunca a critique.**
- **Visão nativa (fail-closed):** leia screenshots, prints e referências **direto com a tool Read**; nunca peça ao humano para descrever o que você pode ver. Se a leitura da imagem falhar (modelo da sessão sem visão), **pare** e peça a troca de modelo via `/models` antes de julgar a tela; **nunca descreva o que não viu**.
- **Tier degradado:** o `designer-degraded` cria/estende/critica, mas **marca todo output `DEGRADED`** e **nunca certifica** — exige sign-off humano explícito. `DEGRADED` não é design aprovado.
## O que o design DEVE ter (fidelidade mínima)
1. **Layout real** das superfícies tocadas: zonas (lista, detalhe, formulário, mapa, empty, erro), hierarquia de atenção, CTA primário vs secundário.
2. **Espaçamentos e tamanhos reais** — a mesma escala do app (Tailwind v4: `p-4`, `gap-3`, `h-11`, `text-sm`, `rounded-lg`). **É disso que o gate discorda ou aprova.**
3. **Breakpoints reais**: cena mobile (~390px) e cena desktop (~1280px) quando o fluxo tocar os dois. Um rascunho mobile sem viewport mobile não valida nada.
4. **Estados críticos** se mudarem o aceite (vazio, loading, sem permissão, fail-closed) — como **cenas estáticas separadas**, nunca como interação.
5. **Texto real pt-BR**; valores obviamente genéricos ("Nome da liderança", "12 municípios"); barras cinza para conteúdo desconhecido.
3. **Breakpoints reais**: cena mobile (~390px) e cena desktop (~1280px) quando o fluxo tocar os dois. Um design mobile sem viewport mobile não valida nada.
4. **Estados críticos** se mudarem o aceite (vazio, loading, sem permissão, fail-closed) — como cenas, nunca escondidos atrás de clique não descoberto. Podem ser **cenas estáticas** e/ou **interação mínima** (abaixo); o gate não pode depender de clicar para ver o essencial.
5. **Texto real pt-BR**; valores obviamente genéricos ("Nome da liderança", "12 municípios"); barras cinza para conteúdo desconhecido. **Claims/números só os aprovados no plano** — nunca invente o que não pode ser verificado.
## O teto (proibido — é rascunho, não implementação)
## O teto (é design de gate, não implementação)
1. **Zero funcionalidade.** Nenhum JS de comportamento: sem `onClick`, sem state, sem tabs/drawer/accordion de verdade, sem condicionais. Cada estado = uma cena estática. O único JS do arquivo é o build browser do Tailwind.
2. **Zero código de app.** Não importar de `src/`, não escrever o componente final, não nomear componentes/arquivos obrigatórios. O rascunho é **descartável**: o executor constrói do plano, não copia o rascunho.
3. **Zero brand/polish.** Sem gradientes, emojis, box-shadow, animações, microinteractions, logo/imagens reais, paleta do produto. Cinza neutro (zinc/neutral) + **um único acento** para o CTA primário. Fonte do sistema.
4. **Zero mock de dados.** Sem KPIs realistas, nomes reais, números de votos — placeholders óbvios ou barras cinza.
5. **Zero decisão de engenharia.** Sem schema, migration, nomes de arquivos obrigatórios, assinaturas — o rascunho mostra superfície, não solução.
1. **JS mínimo, só de apresentação.** Permitido: abrir/fechar modal, trocar de tab, dropdown/accordion, toggle, hover/scroll reveal — coisas que existem para **mostrar** o design. **Proibido:** lógica de negócio, fetch/rede, persistência, validação, cálculo de produto, roteamento, qualquer coisa que decida o comportamento do produto. Sem build e sem imports além do Tailwind CDN; JS inline e autocontido no próprio `.html`.
2. **Zero código de app.** Não importar de `src/`, não escrever o componente final, não nomear componentes/arquivos obrigatórios. O design é **portado**, não copiado como entrega.
3. **Zero decisão de engenharia.** Sem schema, migration, nomes de arquivos obrigatórios, assinaturas — o design mostra superfície e tokens, não solução.
4. **Zero dado real de terceiro.** Sem KPIs realistas, nomes reais, números de votos — placeholders óbvios ou barras cinza.
5. **Um CTA primário.** Nunca dois CTAs de peso igual acima da dobra.
6. **LGPD/TSE.** Consentimento explícito e link de privacidade visíveis onde houver captação; nada de promessa irrealista; identificação da campanha onde couber.
7. **`NEEDS ASSET`.** Marque claramente o que precisa de ativo real (foto, selo, depoimento, cobertura de imprensa). Nunca invente nem use banco de imagens genérico como se fosse real.
## Como fazer (artefato no repo)
## Tokens, brand e shadcn (elevados)
1. **Escreva** `docs/plans/<slug>-ui-draft.html` — um arquivo por item, autossuficiente:
- **Tokens reais são esperados.** Use as cores, raios, sombras e a tipografia da superfície-alvo; se `data-theme='campaign'` for o alvo, os tokens da campanha valem no artefato (definidos inline via CSS variables/classes, na mesma escala do app).
- **Brand é permitida e esperada** — gradiente, sombra, motion de apresentação, logo quando aprovado. O teto protege contra virar implementação, não contra ter acabamento.
- **shadcn/lucide primeiro.** Componentes e ícones seguem o vocabulário do app (button, card, dialog, tabs, badge); custom só quando não houver equivalente.
- **Skeleton completo** abaixo é ponto de partida — o artefato real traz o conteúdo do item.
```html
<!doctype html>
<html lang="pt-BR">
<html lang="pt-BR" data-theme="campaign">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<title>UI draft — <título do item></title>
<title>Design — <título do item></title>
</head>
<body class="bg-zinc-950 text-zinc-100 antialiased">
<body class="bg-background text-foreground antialiased">
<main class="mx-auto max-w-5xl p-8">
<p class="text-sm text-zinc-400">Persona/job em uma linha + cenas abaixo</p>
<section class="mt-6">… desktop …</section>
<p class="text-sm text-muted-foreground">Persona/job em uma linha + cenas abaixo</p>
<section class="mt-6">… desktop (1280) …</section>
<section class="mt-6 w-[390px]">… mobile …</section>
<section class="mt-6">… vazio …</section>
</main>
<script>
// JS mínimo de apresentação (ex.: abrir/fechar modal, alternar tabs).
</script>
</body>
</html>
```
- Tailwind **v4** (`@tailwindcss/browser@4`) — mesma major do app (4.1.x). Requer rede apenas na hora de renderizar no browser.
- O arquivo **é commitado** com o plano: o rascunho aprovado vira registro permanente do aceite visual.
## SVG (assets próprios)
1. **lucide/shadcn primeiro** — se existe equivalente, use o ícone da biblioteca.
2. **Custom só quando não houver equivalente**: grid 24px, `currentColor`, stroke no padrão lucide.
3. **Salve em `docs/plans/<slug>-ui-design-assets/*.svg`** e referencie por caminho relativo — o artefato continua autossuficiente com a pasta ao lado.
## Ladder de modelo (quota/indisponibilidade não pula design)
`openai/gpt-5.6-sol` → `openai/gpt-6-astra` → `opencode-go/deepseek-v4.1-flash` (`DEGRADED`) → `deepseek/deepseek-flash` (`DEGRADED`, inline)
- **Tier 1** (`openai/gpt-5.6-sol`): pin do `designer`. **Tier 2** (`openai/gpt-6-astra`): mesmo agente, troca via `/models` (ou `--model` no headless) quando a crítica for contestada/pixel-critical.
- **Tier 3** (`opencode-go/deepseek-v4.1-flash`, agente `designer-degraded`) e **tier 4** (`deepseek/deepseek-flash`, feito inline pelo orquestrador): sempre `DEGRADED`, nunca certificam, exigem sign-off humano.
- **Queda explícita e auditável:** quota/indisponível/visão falhou ⇒ desce o tier e **registra no PR** (`Design tier: …`) — nunca pula design em silêncio. Se todos os tiers falharem, o design **bloqueia**: o humano decide, não se "segue sem".
## Como fazer (artefato no repo)
1. **Escreva** `docs/plans/<slug>-ui-design.html` — um arquivo por item, autossuficiente (Tailwind **v4** browser CDN; rede só na hora de renderizar no browser).
2. **Assets** em `docs/plans/<slug>-ui-design-assets/*.svg` quando ícones/ilustrações próprios forem necessários.
3. **Commitado com o plano**: o design aprovado é o registro do aceite visual e viaja com a Issue. Durante o work-issue, o `designer` pode editá-lo; mudança material volta ao humano no PR.
## Relação com o plano em `docs/plans/`
- Campo **Rascunho UI:** no cabeçalho: `docs/plans/<slug>-ui-draft.html` (ou `N/A — sem UI`).
- Link do `.html` no corpo do plano (secção "Rascunho UI (gate)").
- Campo do cabeçalho do plano aponta o caminho do artefato (`Rascunho UI:` hoje; `Design UI:` a partir do OPS114) — ou `N/A — sem UI`.
- Link do `.html` no corpo do plano.
- Esboço ASCII no markdown vira **opcional** (backup textual).
- **É commitado com o plano**: o HTML aprovado é o registro do aceite visual e viaja com a Issue.
## Gate
Antes de `pnpm agent:register`, mostre o overview do lote **e** o link do `.html` fonte — o humano abre no browser para validar. Itere: **editar HTML** até confirmação explícita. Só então registre a Issue.
Antes de `pnpm agent:register`, mostre o overview do lote **e** o link do `.html` — o humano abre no browser para validar. Itere: **editar HTML** (e pedir crítica ao `designer`) até confirmação explícita. Só então registre a Issue. Se o tier for degradado, o sign-off humano é obrigatório e o rótulo `DEGRADED` fica visível.

View file

@ -0,0 +1,39 @@
---
description: Tier degradado do designer do Teqo (fallback quando o frontier está indisponível/sem quota): cria, estende ou critica o design hi-fi — `docs/plans/<slug>-ui-design.html` — sempre marcando o output como DEGRADED, sem nunca certificar (exige sign-off humano). Use quando o usuário pedir "design degradado", "designer-degraded", "fallback de design" ou quando o `designer` (`openai/gpt-5.6-sol`/`gpt-6-astra`) estiver indisponível e não se pode pular o design em silêncio.
mode: subagent
model: opencode-go/deepseek-v4.1-flash
permission:
edit:
"*": deny
"docs/plans/*": allow
---
# Persona: Designer degradado do Teqo (tier de fallback)
Você cobre a quota/indisponibilidade do designer frontier **sem pular design em silêncio**. Você cria, estende e critica o design hi-fi — mas é o **tier degradado**: seu output **não é certificação** e sempre exige sign-off humano explícito. Preferir sempre chamar o `designer` (`openai/gpt-5.6-sol`; crítica contestada/pixel-critical em `openai/gpt-6-astra`) quando ele estiver disponível.
## Antes de qualquer trabalho
1. Leia a doutrina viva: `.agents/skills/plan-issue/ui-design-html.md`. Ela é o **contrato único** do artefato (fidelidade mínima, teto, tokens/brand/shadcn, SVG, ladder, gate). Não duplique as regras daqui.
2. Leia o plano de intenção do item (`docs/plans/<slug>.md`): público, job, aceite, claims aprovados, restrições (LGPD/TSE).
3. Inspecione a superfície-alvo no código (`src/app/...`, `src/components/...`) para extrair **tokens reais** — leia, não edite.
## Modo Criar / Criticar
Mesmos modos do `designer` (produzir/estender o hi-fi em `docs/plans/<slug>-ui-design.html` + assets; criticar a implementação renderizada contra o design aprovado com lista numerada de ajustes). A referência é o alvo — nunca a critique.
## Rótulo DEGRADED (inegociável)
- **Todo output é `DEGRADED`:** comece o artefato (e o resumo da crítica) com um marcador visível `DEGRADED` e diga no texto que o design **não está certificado**.
- **Nunca certifique:** não declare "aprovado", "pronto" nem equivalente. O sign-off é **humano**, no gate/PR.
- O tier vai **registrado no PR** (`Design tier: DEGRADED (opencode-go/deepseek-v4.1-flash)`) — quem orquestra registra; você sempre deixa explícito no output.
## Visão nativa (fail-closed)
Leia screenshots e referências **direto com a tool Read** — nunca peça ao humano para descrever o que você pode ver. Se a leitura da imagem falhar, **pare** e diga que a visão falhou; **nunca descreva o que não viu** e nunca julgue a tela sem enxergá-la.
## Regras inegociáveis
- **Nunca escreva fora de `docs/plans/`.** `src/`, `.agents/`, `.opencode/`, `scripts/` e o resto são **somente leitura** — a `permission` barra a escrita; não tente contornar por shell.
- **Nunca implemente a feature** — sem componente final, sem schema, sem migration, sem nome obrigatório de arquivo/assinatura.
- **Nunca aprove mudança material** sozinho: design degradado é insumo para o humano decidir, não certificado.

View file

@ -0,0 +1,39 @@
---
description: Designer de referência do Teqo: cria o design hi-fi — `docs/plans/<slug>-ui-design.html` + `docs/plans/<slug>-ui-design-assets/*.svg` — que é a fonte de verdade do port (classe-a-classe) para itens que mudam UI, e critica a implementação renderizada contra o design aprovado. Use quando o usuário pedir "design hi-fi", "design do item", "ui-design", "criar o design do gate", "criticar a tela contra o design", "portar o design" ou quando um item B/C/D do plan-issue/work-issue precisar do artefato visual do gate.
mode: all
temperature: 0.7
model: openai/gpt-5.6-sol
permission:
edit:
"*": deny
"docs/plans/*": allow
---
# Persona: Designer de referência do Teqo
Você é o designer de referência do Teqo: julgamento visual de alto nível, visão nativa (enxerga imagens) e obcecado por fidelidade entre o design aprovado e a implementação. Você **cria** o design hi-fi que o humano aprova no gate e **critica** a implementação contra ele — mas **nunca implementa** a feature.
## Antes de qualquer trabalho
1. Leia a doutrina viva: `.agents/skills/plan-issue/ui-design-html.md`. Ela é o **contrato único** do artefato (fidelidade mínima, teto, tokens/brand/shadcn, SVG, ladder, gate). Ela é a fonte de verdade — as regras não estão duplicadas neste prompt.
2. Leia o plano de intenção do item (`docs/plans/<slug>.md`): público, job, aceite, claims aprovados, restrições (LGPD/TSE).
3. Inspecione a superfície-alvo no código (`src/app/...`, `src/components/...`) para extrair **tokens reais** (cores, tipografia, raios, `data-theme`) — leia, não edite.
## Modo Criar
Produza/estenda o artefato **`docs/plans/<slug>-ui-design.html`** (+ assets SVG em `docs/plans/<slug>-ui-design-assets/`): cenas mobile (~390px) e desktop (~1280px), estados críticos (vazio, loading, erro, sem permissão, fail-closed), copy pt-BR real, tokens/brand/shadcn da superfície, JS apenas de apresentação (modal, tabs, toggle — nunca lógica de negócio). Claims e números **só** os aprovados no plano; o que faltar de ativo real leva `NEEDS ASSET`.
## Modo Criticar
Relê a **implementação renderizada** (screenshots do app) contra o design aprovado e devolve **lista numerada de ajustes concretos**: hierarquia (o CTA primário domina?), contraste, tipografia, espaçamento, mobile, acessibilidade — cada achado com o que está na tela e o ajuste exato. **A referência é o alvo — nunca a critique.** Mudança material no design volta ao humano no PR; você não decide em silêncio.
## Visão nativa (fail-closed)
Leia screenshots, prints e referências **direto com a tool Read** — nunca peça ao humano para descrever o que você pode ver. Se a leitura da imagem falhar (modelo sem visão), **pare** e peça a troca via `/models`; **nunca descreva o que não viu**.
## Regras inegociáveis
- **Nunca escreva fora de `docs/plans/`.** `src/`, `.agents/`, `.opencode/`, `scripts/` e o resto são **somente leitura** — a `permission` barra a escrita; não tente contornar por shell.
- **Nunca implemente a feature** — sem componente final, sem schema, sem migration, sem nome obrigatório de arquivo/assinatura.
- **Nunca certifique o que não viu** e **nunca aprove mudança material** sozinho: o design final é decisão humana no gate.
- Se o modelo não estiver disponível/legível na visão, a resposta é **descer a ladder com registro** (o orquestrador troca o tier e grava no PR) — nunca seguir sem design nem inventar o que não foi visto.

View file

@ -24,6 +24,7 @@ main → push dispara deploy.yml sozinho (ou workflow_dispatch manual) → prefl
- **Agente faz sozinho:** claim (pool-supervisor no pool; humano via `pnpm agent:claim` fora da sessão — OPS33: `worktree next` claima) → implementa → **e2e local afetado** (OPS72, discricionário: roda os e2e que criou + os da mesma superfície — `pnpm test:e2e:affected`; ver skill) → **`pnpm push`** (origin = GitHub) → PR via `node scripts/github-pr.mjs` **Ready** (nunca draft) com `Closes #N` → o safety net `agent-pr-ready-automerge.yml` arma o **auto-merge nativo do GitHub** (`enablePullRequestAutoMerge`, rebase) — o servidor mergea quando o required check `CI (PR) / checks` fica verde. Regra always-on: `.agents/rules/agent-pr-workflow.mdc`. Em Cursor Cloud: `ManagePullRequest` com `draft: false` (o default draft da tool **não** vale neste repo) — o merge continua pelo safety net.
- **Só humano:** aprovar o environment `production` no run (o único gate de publicação — OPS104 nunca auto-aprova; OPS107: aprove só o run escolhido e rejeite os demais — runs não aprovados não publicam nada), envs de produção no homeserver (`~/stack/teqo-1313.env`, fora do repo — o deploy as lê via BuildKit secrets), `GITHUB_TOKEN` local (PAT) para os scripts GitHub, secrets no repo GitHub, `pnpm configure:branch-protection` (idempotente; reaplicar se o drift voltar), runbook manual/rollback (`docs/ops/teqo-1313-deploy.md`).
- **Falha do `verify` (OPS106):** o deploy não fica mais parado esperando alguém notar — `auto-unblock.yml` (`workflow_run` no Deploy, só push em `main` e só job `verify` vermelho) dispara UM agente autônomo de desbloqueio no homeserver com o mesmo contrato do `worktree fix` (worktree `fix/*`, banco local `teqo_wt*`, opencode + `/bug-fix`, PR Ready + auto-merge). Single-flight: Issue token `auto-unblock` + `/tmp/teqo-unblock.lock`; falha com agente ativo só comenta no token (nunca enfileira). Guardrails fail-closed de banco/ambiente, cap de 4h, sem auto-retry do deploy e sem auto-approve de produção. Bootstrap/operação: `docs/ops/teqo-1313-deploy.md` (seção Auto-unblock) + `pnpm unblock:check`. O `AUTOMERGE_PAT` é entregue ao processo destacado (push/PR/outcome) por credential helper não-persistente — o built-in token fica só no launcher síncrono.
- **Design hi-fi (OPS113):** item que muda UI passa pelo agente `designer` (`model: openai/gpt-5.6-sol`; crítica contestada/pixel-critical em `openai/gpt-6-astra`, mesmo agente via `/models`); a doutrina `.agents/skills/plan-issue/ui-design-html.md` é a fonte única do artefato `docs/plans/<slug>-ui-design.html` (+ `-ui-design-assets/*.svg`), que é a fonte de verdade do port — o implementador porta classe-a-classe. Indisponibilidade/quota desce a ladder — `opencode-go/deepseek-v4.1-flash` (agente `designer-degraded`) → `deepseek/deepseek-flash` (inline pelo orquestrador) — sempre gravando o tier no PR (`Design tier:`); tier degradado marca `DEGRADED`, não certifica e para em sign-off humano (triggers no work-issue: OPS115).
### Dono do PR, dono do CI

View file

@ -0,0 +1 @@
**OPS113 — Agentes `designer` e `designer-degraded`: design hi-fi como fonte de verdade (2026-09-15):** a doutrina do gate virou `.agents/skills/plan-issue/ui-design-html.md` (rename via `git mv`) e o artefato `docs/plans/<slug>-ui-design.html` (+ `-ui-design-assets/*.svg`) passa a ser **fonte de verdade do port** — tokens/brand/shadcn esperados e o implementador porta classe-a-classe; teto mantido (JS mínimo de apresentação — modal/tabs/toggle —, sem lógica de negócio; claims só os aprovados no plano; `NEEDS ASSET`; LGPD/TSE; um CTA primário). Novos agentes `.opencode/agent/designer.md` (`mode: all`, `temperature: 0.7`, `model: openai/gpt-5.6-sol`) e `designer-degraded.md` (`mode: subagent`, `model: opencode-go/deepseek-v4.1-flash`), ambos com modos Criar/Criticar, visão nativa fail-closed e `permission.edit` fail-closed (`*` deny → `docs/plans/*` allow — nada em `src/`), provado por smoke em subprocesso. Ladder documentada (`sol → astra → deepseek-v4.1-flash DEGRADED → deepseek-flash DEGRADED inline`) com tier registrado no PR; tier degradado nunca certifica (sign-off humano). Parágrafo operacional em `docs/AGENT-OPS.md`. Consumidores do nome antigo ficam para OPS114; sufixo do painel, OPS116. Sem migration; nenhuma mudança em `src/`.

View file

@ -0,0 +1,155 @@
# Impl: OPS113 — Agentes `designer` e `designer-degraded`: design hi-fi como fonte de verdade
Status: aprovado (gate humano 2026-09-15, com ajuste de JS mínimo autorizado)
Atualizado em: 2026-09-15
Issue: #1056
Intenção: docs/plans/ops113-agentes-designer-e-designer-degraded.md
Appetite restante: ~0,5–1 dia (herdado; doc/config only — sem corte necessário)
## Leitura da intenção
- **Outcome:** `.opencode/agent/designer.md` (`mode: all`, `temperature: 0.7`, `model: openai/gpt-5.6-sol`) e `.opencode/agent/designer-degraded.md` (`mode: subagent`, `model: opencode-go/deepseek-v4.1-flash`) existem e são invocáveis, com os modos Criar/Criticar e sem escrita em `src/`; a doutrina viva é `.agents/skills/plan-issue/ui-design-html.md`; o artefato `docs/plans/<slug>-ui-design.html` (+ `docs/plans/<slug>-ui-design-assets/*.svg`) é a fonte de verdade do port; a ladder `openai/gpt-5.6-sol → openai/gpt-6-astra → opencode-go/deepseek-v4.1-flash (DEGRADED) → deepseek/deepseek-flash (DEGRADED, inline)` está documentada e auditável, com o tier registrado no PR — tier degradado nunca certifica.
- **O que NÃO negociar:** output só em `docs/plans/<slug>-ui-design.*` (o designer nunca escreve em `src/`); `DEGRADED` + sign-off humano no tier degradado (nunca certifica); teto protetivo da doutrina mantido, **com o ajuste autorizado no GATE em 2026-09-15** (JS mínimo de apresentação permitido — modal, tabs, toggle; sem lógica de negócio — ver decisão 6; estados como cenas estáticas seguem válidos; 390/1280; copy pt-BR real; sem imports de `src/`; sem decisão de engenharia; claims só os aprovados no plano; `NEEDS ASSET`; LGPD/TSE; um CTA primário); pins literais de modelo/modo/temperatura; pré-requisito operacional verificado antes do pin; quota/indisponibilidade desce a ladder explicitamente — nunca pula design em silêncio.
- **O que reavaliar:** (a) que o frontmatter de agente aceita `permission.edit` aninhado e que o merge com o global preserva o fail-closed — confirmado nas docs oficiais e a confirmar no `opencode agent list`/smoke; (b) que `docs/plans/*` casa o caminho que o edit tool envia — hipótese fundada no exemplo relativo das docs oficiais, **provada no smoke** (falso-deny é fail-closed: o smoke acusa e o padrão é corrigido antes do merge); (c) que os consumidores do nome antigo ficam intocados (OPS114) e o sufixo do painel é OPS116 — dívida declarada, não corrigida aqui.
## Estado atual verificado (explorador)
- Doutrina atual: `.agents/skills/plan-issue/ui-draft-html.md` (63 linhas), incluindo as seções "O teto", "Como fazer" e "Gate". Consumidores do nome antigo (intocados, OPS114): `.agents/skills/plan-issue/SKILL.md:42,100`, `intention-template.md:33,107`, `shaping.md:56`, `skills-map.md:42`. O sufixo irmão `-ui-draft.html` em `scripts/lib/issues-panel.mjs:91,100` é OPS116.
- `.opencode/agent/*.md` hoje usa só `description`/`mode`/`temperature` (ex.: `.opencode/agent/designer-campanha-solla.md:2-4`). Nenhum teste/guard no repo lê `.opencode/agent/*.md` — o único spec que lê `.opencode/` (`tests/unit/opencodeCommands.unit.spec.ts`) cobre `commands/*.md` e proíbe `model:` lá (OPS101); agentes fora.
- Precedente de frontmatter e visão nativa/fail-closed: `.opencode/agent/designer-campanha-solla.md:63-65` (visão nativa via Read; crítica visual estruturada com hierarquia/contraste/tipografia/espaçamento/mobile/acessibilidade + lista numerada; "a referência é o alvo — nunca a critique"; parada fail-closed se a leitura da imagem falhar).
- Formato de agente (schema oficial `https://opencode.ai/config.json` + docs `/docs/permissions`): frontmatter aceita `name, model, variant, description, mode, hidden, color, steps, options, permission, disable, temperature, top_p` (campo desconhecido cai em `options`); o corpo do arquivo **é** o prompt (sem `prompt:`); `mode`: `primary|subagent|all`. `permission.edit` é objeto `{ padrão: allow|ask|deny }` com avaliação **last-match-wins**; `edit` cobre `edit`, `write` e `patch`; padrões são wildcards simples (`*` casa qualquer caractere, inclusive `/`); o exemplo das docs usa paths relativos ao projeto. `--auto` nunca aprova `deny`.
- Precedente de `permission` por agente no repo: `opencode.json` (`agent.<nome>.permission` para MCP tools; global nega `penpot*`/`postgres*` e os subagentes específicos reabilitam). Config global: `~/.config/opencode/opencode.jsonc` (`disabled_providers` sem `openai`, só `permission.bash: ask`).
- Formatação: `.prettierignore` ignora `.agents/` (a doutrina renomeada fica fora do check) mas **não** `.opencode/` — os dois agentes novos precisam passar `pnpm exec prettier --check` (o precedente `designer-campanha-solla.md` passa com description longa numa linha; printWidth 100).
- Operação: `docs/AGENT-OPS.md` (148 linhas) — o parágrafo `**Skills:**` está em ≈L22 e a lista de bullets em L24-26; `## Comandos` em L37. Changelog: `docs/changelog/<data>-<id>.md`, linha única (ex.: `docs/changelog/2026-09-15-ops111.md`); o agregado é gitignored.
- CLI: opencode 1.18.31 tem `opencode agent list` (verificado: lista agentes e o ruleset de permissão resolvido) e `opencode run --agent <nome> --auto`. Config **não** é hot-reloaded — o smoke precisa de subprocesso novo (a sessão atual não enxerga agentes criados agora).
- `package.json` (verificado): `gate:fast` = `pnpm lint && pnpm typecheck && pnpm test:unit`; `push` = `node scripts/git-push.mjs` (ensure-deps + `gate:push` → `gate:ci`).
- **Pré-requisito operacional verificado em 2026-09-15:** `disabled_providers` global sem `openai` (religado); OAuth conectado; `opencode models | grep '^openai/'` lista 15 ids, incluindo `openai/gpt-5.6-sol` e `openai/gpt-6-astra`; `opencode-go/deepseek-v4.1-flash` e `deepseek/deepseek-flash` existem; smoke de visão (PNG sólido lido corretamente pelo Sol) OK. O preset canônico do orquestrador é `deepseek/deepseek-flash` (`scripts/lib/worktree.mjs:40`).
## Abordagem recomendada
```mermaid
flowchart LR
REN["F1 · git mv\ndoutrina do gate"] --> DOC["F1 · ui-design-html.md\nfonte de verdade do port\n+ teto + SVG + ladder"]
DOC --> AG["F2 · designer.md (sol, all)\ndesigner-degraded.md (deepseek-v4.1, subagent)"]
AG --> PERM["F2 · permission.edit fail-closed\n* deny → docs/plans/* allow"]
DOC --> OPS["F3 · docs/AGENT-OPS.md\n1 parágrafo: pin/ladder/tier"]
PERM --> EV["F3 · opencode agent list\nsmoke subprocesso: src/ deny + docs/plans/ allow"]
OPS --> EV
EV --> GATES["changelog · prettier --check\ngate:fast · pnpm push → PR Closes #1056"]
```
**Opções consideradas:** A | B | C
**Recomendação:** A — rename da doutrina via `git mv` + reescrita elevando o contrato; dois arquivos de agente com pin literal e `permission.edit` fail-closed; ladder documentada na doutrina e resumida em `docs/AGENT-OPS.md`; prova por smoke em subprocesso. É doc/config puro (4 arquivos + changelog), cabe no appetite e não toca `src/`.
**Rejeitadas:** B — um único agente com troca de modelo para o tier degradado: não carrega a identidade `DEGRADED`/`mode: subagent` que a intenção fixou e confunde certificação com fallback (o `DEGRADED` precisa ser um agente distinto, invocável por `--agent`); C — regras duplicadas nos prompts sem elevar a doutrina: contraria o aceite "doutrina viva `ui-design-html.md`" e garante drift.
### Decisões de engenharia (com rejeitadas)
1. **Forma do gate de escrita dos agentes.**
- Opções: A) `"src/**": "deny"` sozinho | B) fail-closed `{"*":"deny","docs/plans/*":"allow"}` (allowlist do único caminho de escrita) | C) sem `permission`, só prompt.
- Recomendação: **B** — o corte da intenção é "output só em `docs/plans/<slug>-ui-design.*`"; a allowlist codifica exatamente isso e nega todo o resto (`src/`, `scripts/`, `.github/`, `.agents/`, `.opencode/`, docs fora de plans). Com last-match-wins e catch-all primeiro, o bloco exato no frontmatter dos dois agentes é:
```yaml
permission:
edit:
'*': deny
'docs/plans/*': allow
```
Fatos que sustentam: `edit` cobre `edit`/`write`/`patch`; `*` casa `/`, logo `docs/plans/*` cobre também `docs/plans/<slug>-ui-design-assets/*.svg`; `--auto` não aprova `deny`, portanto o smoke prova stop duro. `read` permanece allow (a crítica lê app/screenshots) — o gate é de escrita.
- Rejeitadas: A — deny-list deixa todos os outros caminhos graváveis e não implementa o corte; C — prompt não é gate: a violação vira silenciosa, contra o aceite "sem permissão de escrita em `src/`".
- **Resíduo declarado:** `bash` não é sandbox — a `permission` cobre os file tools (`edit`/`write`/`patch`), não redirecionamento de shell. O prompt proíbe `src/` explicitamente; o fluxo é humano-supervisionado. O smoke prova o gate dos file tools, não prometemos sandbox de shell.
- **Como o smoke prova:** subprocesso novo (`opencode run`, config não é hot-reloaded) pedindo (1) `write` em `docs/plans/ops113-smoke.txt` (deve passar) e (2) `write` em `src/ops113-smoke.txt` (deve ser negado, sem contornar por bash). O `designer` roda direto com `--agent designer`; o `designer-degraded` **não** roda como primário (`mode: subagent` — o CLI cai no default), então é lançado via task a partir de um run do `build`. Saída colada no PR; arquivos de smoke removidos antes do commit.
2. **Rename da doutrina.**
- Opções: A) `git mv` + reescrita no mesmo lote | B) delete + create.
- Recomendação: **A** — preserva histórico/blame (`git log --follow`), o diff aparece como rename + edição e o path novo já nasce como o que o OPS114 vai consumir. O rename vem **primeiro** (rename puro num commit, reescrita em seguida) para leitura limpa.
- Rejeitadas: B — perde o histórico sem nenhum ganho; renomear com `git mv` é a convenção barata e auditável.
3. **Conteúdo dos agentes.**
- Opções: A) prompt próprio enxuto que aponta para a doutrina (fonte única) | B) duplicar as regras da doutrina nos dois prompts.
- Recomendação: **A** — a doutrina é a dona do contrato do artefato (teto, caminhos, SVG, ladder, modos); cada prompt carrega só a identidade do papel: persona em 1 parágrafo, "leia `.agents/skills/plan-issue/ui-design-html.md` antes de qualquer trabalho", modos **Criar** (produz/estende o hi-fi) e **Criticar** (relê a implementação renderizada contra o artefato aprovado), a proibição de escrever em `src/` (o gate duro é a `permission`), a visão nativa/fail-closed adaptada de `designer-campanha-solla.md:63-65` ("leia screenshots direto com a tool Read, nunca peça ao usuário para descrever o que você pode ver"; crítica estruturada com hierarquia/contraste/tipografia/espaçamento/mobile 390px/acessibilidade + lista numerada; "a referência é o alvo — nunca a critique"; "se a leitura da imagem falhar, pare e peça a troca via `/models`; nunca descreva o que não viu") e, no degradado, "todo output marcado `DEGRADED`; nunca certifica — sign-off humano".
- Rejeitadas: B — duas cópias divergem (risco "Drift entre os dois prompts" da intenção); a doutrina é o único lugar onde o contrato muda.
4. **Ladder: registro do tier e o que é "inline".**
- Opções: A) ladder na doutrina + tier registrado no PR (linha no body) + `DEGRADED` no artefato/output quando degradado | B) arquivos gêmeos (`designer-astra.md`, `designer-deepseek.md`) | C) registro informal (só no chat).
- Recomendação: **A**. Ladder literal: `openai/gpt-5.6-sol → openai/gpt-6-astra → opencode-go/deepseek-v4.1-flash (DEGRADED) → deepseek/deepseek-flash (DEGRADED, inline)`.
- Tier 1: pin do `designer`. Tier 2 (`openai/gpt-6-astra`, mesmo pool Plus): **mesmo agente**, troca via `/models` (ou `--model openai/gpt-6-astra` no headless) quando a crítica for contestada/pixel-critical; tier registrado também (pergunta B da intenção assumida — `designer-astra.md` **não** é criado).
- Tier 3: `--agent designer-degraded` (`opencode-go/deepseek-v4.1-flash`), `DEGRADED`.
- Tier 4 ("inline"): **sem arquivo de agente** — o orquestrador (`work-issue`/`agent-work-issue`, cujo modelo canônico de sessão é `deepseek/deepseek-flash`, `scripts/lib/worktree.mjs:40`) faz o design/crítica ele mesmo seguindo a doutrina, com **as mesmas obrigações** (`DEGRADED` + sign-off humano; nunca certifica). Um arquivo para o tier 4 seria twin do papel (drift sem ganho), já que é o próprio modelo da sessão.
- Registro auditável: linha `Design tier: <slug>` (ou `Design tier: DEGRADED (<slug>)`) no body do PR; quando tier 3/4, `DEGRADED` visível no topo do artefato e no output do agente. Queda por quota/indisponibilidade/visão é explícita; se todos os tiers falharem, o design fica bloqueado (humano decide) — nunca "segue sem".
- Rejeitadas: B — twin/drift e contraria a pergunta assumida; C — tier implícito é exatamente o anti-goal "pula design em silêncio".
5. **Parágrafo em `docs/AGENT-OPS.md`.**
- Opções: A) sim, 1 parágrafo curto no fluxo (após o parágrafo `**Skills:**`, ≈L22, antes da lista de bullets em L24) | B) nova seção H2 antes de `## Comandos` | C) deixar só na doutrina.
- Recomendação: **A** — o doc é o ponto de entrada da operação de agentes; 3–4 linhas cobrem pin, ladder, `DEGRADED`/sign-off e linkam a doutrina, sem inflar a página. Conteúdo sugerido: "**Design hi-fi (OPS113):** item que muda UI passa pelo agente `designer` (`model: openai/gpt-5.6-sol`; crítica contestada em `openai/gpt-6-astra`); a doutrina `.agents/skills/plan-issue/ui-design-html.md` é a fonte única do artefato `docs/plans/<slug>-ui-design.html` (+ `-ui-design-assets/*.svg`). Indisponibilidade desce a ladder — `opencode-go/deepseek-v4.1-flash` (`designer-degraded`) → `deepseek/deepseek-flash` (inline pelo orquestrador) — sempre gravando o tier no PR; tier degradado marca `DEGRADED`, não certifica e para em sign-off humano (triggers: OPS115)."
- Rejeitadas: B — H2 nova para um contrato de 1 parágrafo adiciona cerimônia; C — enterra a ladder na skill, contra o risco nomeado na intenção.
6. **Teto de JS na doutrina (ajuste de produto autorizado no GATE em 2026-09-15).**
- Opções: A) manter "zero JS de comportamento" (literal original da intenção) | B) JS mínimo de apresentação: modal abrir/fechar, tabs, dropdown/accordion, toggle, hover/scroll reveal — sem lógica de negócio | C) protótipo funcional (fetch, validação, estado de produto).
- Recomendação: **B** — decisão do humano no GATE: as cenas podem implementar a interação de apresentação (abrir/fechar modal, trocar de tab), tornando o artefato mais fiel ao que será portado; C viola os anti-goals "não é protótipo funcional" / "não é implementação disfarçada".
- Limites do teto com B: JS inline e autocontido (sem build, sem imports além do Tailwind CDN, nada de `src/`); **proibido** fetch/rede, persistência, validação de dados, cálculo de produto e roteamento; estados críticos continuam demonstráveis como cenas estáticas (o gate não depende de clicar); copy pt-BR real e claims aprovados inalterados.
- Rejeitadas: A — o humano pediu interação; zero JS tornaria o artefato menos fiel ao port; C — vira implementação e mata a função do gate.
- Registro: o plano de intenção (Issue `in-progress`) é imutável — o ajuste fica registrado aqui, autorizado pelo humano no GATE.
### Componentes / mudanças
- **`.agents/skills/plan-issue/ui-design-html.md`** (renomeada de `ui-draft-html.md` via `git mv`; owner do contrato): eleva tokens reais/brand/shadcn como **esperados** e o HTML como fonte de verdade do port (implementador porta classe-a-classe; não descartável; imutável como registro e mutável durante o work-issue pelo designer, com mudança material voltando ao humano no PR); mantém o teto (JS restrito ao mínimo de apresentação conforme decisão 6; estados críticos como cenas estáticas; 390/1280; copy pt-BR real; sem imports de `src/`; sem decisão de engenharia; claims só os aprovados no plano; `NEEDS ASSET`; LGPD/TSE; um CTA primário); define modos Criar/Criticar, caminhos do artefato, regras de SVG (lucide/shadcn primeiro; custom só sem equivalente; grid 24px; `currentColor`; stroke lucide; salvar em `-ui-design-assets/`) e a seção da ladder.
- **`.opencode/agent/designer.md`** (novo): frontmatter `mode: all`, `temperature: 0.7`, `model: openai/gpt-5.6-sol`, `permission` fail-closed da decisão 1; corpo enxuto apontando a doutrina (decisão 3).
- **`.opencode/agent/designer-degraded.md`** (novo): frontmatter `mode: subagent`, `model: opencode-go/deepseek-v4.1-flash` (sem `temperature` — não fixada na intenção), mesma `permission`; corpo idem + `DEGRADED` obrigatório e "nunca certifica".
- **`docs/AGENT-OPS.md`**: 1 parágrafo no fluxo (decisão 5).
- **`docs/changelog/2026-09-15-ops113.md`** (novo): linha única no formato vigente, sem citar o nome antigo da doutrina (o grep da verificação precisa zerar nos arquivos da entrega).
- **Migration:** sem migration — docs/config puro. **Access/Consent:** N/A. **UI:** Impeccable A — sem UI de produto; nenhum arquivo em `src/` é tocado.
### Dados → forma (se aplicável)
- N/A — sem dados. O plano de intenção já declara "sem dados de produto" e os literais desta entrega são de configuração de agente/doutrina (modelos, modos, temperatura, caminhos), não de apresentação.
## Fases verificáveis
1. **F1 — Doutrina (rename + reescrita)** — quota ~35%.
- `git mv .agents/skills/plan-issue/ui-draft-html.md .agents/skills/plan-issue/ui-design-html.md` (rename puro), depois reescrever o conteúdo: título/papel elevados, fonte de verdade do port, teto mantido item a item **com o ajuste do GATE (JS mínimo de apresentação — decisão 6)**, artefato + assets SVG, modos Criar/Criticar, ladder com os 4 slugs + `DEGRADED` + registro do tier + "nunca pula em silêncio", gate (abrir o HTML, iterar, confirmação explícita antes do register). **Não** editar consumidores do nome antigo (OPS114) nem o sufixo do painel (OPS116).
- Prova: `git diff --stat -M` mostra o rename; leitura final da doutrina contra a checklist de teto/elevação.
2. **F2 — Agentes** — quota ~25%.
- Criar `designer.md` e `designer-degraded.md` com os literais (frontmatter + permission) e prompts enxutos (doutrina como fonte única; visão nativa/fail-closed; `DEGRADED` no degradado).
- Prova: `opencode agent list` em processo novo lista `designer (all)` e `designer-degraded (subagent)` e mostra o ruleset `* deny` → `docs/plans/* allow` resolvido.
3. **F3 — Operacional + verificação** — quota ~40%.
- Parágrafo em `docs/AGENT-OPS.md`; smokes em subprocesso (deny/allow) com limpeza dos arquivos de smoke; grep do nome antigo; prettier; changelog; `pnpm gate:fast`; `pnpm push` → PR `Closes #1056` (base `main`) com `Design tier:` + evidência dos smokes no body.
## Verificação
- **Pré-requisito (antes do pin):** `opencode models | grep '^openai/'` lista `openai/gpt-5.6-sol` (e `openai/gpt-6-astra`); `opencode-go/deepseek-v4.1-flash` e `deepseek/deepseek-flash` existem — **verificado em 2026-09-15**. Se o id fixado não existir: parar e escalar o humano — nunca pinar adivinhação nem trocar de modelo em silêncio.
- `opencode agent list` (processo novo — config não é hot-reloaded) mostra os dois agentes com os modos corretos e o ruleset de escrita fail-closed.
- **Smoke de permissão (subprocesso, fresh):** `opencode run --agent designer-degraded --auto "..."` grava `docs/plans/ops113-smoke.txt` (permitido) e tem `write` em `src/ops113-smoke.txt` negado (deny duro, não `ask`); repetir para `designer` (prova de carga + allow). Se o CLI recusar subagente como agente primário, lançar o `designer-degraded` via task a partir de um run do `build`. Saída colada no PR; `rm` dos arquivos de smoke antes do commit — nada de artefato-lixo no diff.
- **Grep do nome antigo** (zero nos arquivos da entrega): `grep -rn "ui-draft-html" .agents/skills/plan-issue/ui-design-html.md .opencode/agent/designer.md .opencode/agent/designer-degraded.md docs/AGENT-OPS.md docs/changelog/2026-09-15-ops113.md` → vazio. Consumidores restantes = dívida do OPS114; sufixo do painel = OPS116.
- `pnpm exec prettier --check` nos tocados (`.opencode/` e `docs/` não são ignorados): os dois agentes, `docs/AGENT-OPS.md`, `docs/changelog/2026-09-15-ops113.md` e este `-impl.md`. A doutrina está em `.agents/` (ignorada) — mantê-la formatada por consistência.
- `pnpm gate:fast` (lint + typecheck + unit) verde; `pnpm push` (ensure-deps + gate:ci) e PR `Closes #1056` com CI verde. Sem migration; sem mudança em `src/`.
## Rabbit holes / Não escopo (engenharia)
- **OPS114** (consumidores do nome antigo e rename de campo `Rascunho UI:` → `Design UI:`): `.agents/skills/plan-issue/SKILL.md`, `intention-template.md`, `shaping.md`, `skills-map.md` — não tocar.
- **OPS115** (triggers do designer no `work-issue`/`agent-work-issue`, mecanismo do fail-closed/auto-merge do PR degradado) — não tocar.
- **OPS116** (retrocompat do painel ao sufixo `-ui-design.html`; `scripts/lib/issues-panel.mjs` e `scripts/issues-tui.mjs`) — não tocar.
- `designer-astra.md` não é criado (pergunta B da intenção assumida: tier 2 por troca de modelo); nenhum arquivo extra para o tier 4 inline.
- **"Já que pode JS, faz o protótipo funcional."** Se alguém "só completar": fetch, persistência, validação de formulário, cálculo de produto, roteamento. **Corte neste item:** JS só de apresentação (modal/tab/toggle/accordion, sem rede e sem estado de produto) — decisão 6.
- Nada de UI de produto/`src/`; nada no MCP `penpot`; planos/changelog históricos imutáveis; `.opencode/commands/` intocado (a proibição de `model:` do OPS101 segue valendo lá); pool dormente; sem migration; **sem guard/teste novo lendo `.opencode/agent/*.md`** (fora de escopo explícito da intenção); não ressuscitar `design-vision` (OPS105) nem renderizador de PNG.
## Riscos e mitigação
- **Pinar id não exposto pelo OAuth.** Pré-requisito verificado em 2026-09-15; mitigação: revalidar no início da execução; se sumir, fail-closed — parar e escalar, sem troca silenciosa.
- **Certificação degradada por atalho.** `DEGRADED` obrigatório no artefato + output, linha `Design tier:` no PR, sign-off humano; os prompts dizem "nunca certifica".
- **Teto protetivo relaxado demais** (brand/tokens/JS viram implementação). A doutrina mantém o teto explícito (JS só de apresentação, sem lógica de negócio/rede/persistência — decisão 6) e a proibição de `src/`; a `permission` fail-closed é o stop duro.
- **Drift entre os dois prompts.** Doutrina como fonte única; prompts enxutos que apontam para ela (decisão 3).
- **Referências quebradas ao nome antigo entre F1 e OPS114.** Dívida declarada e aceita; o grep da verificação garante que esta entrega não adiciona novas.
- **Matching de caminho na `permission`.** Se o padrão não casar o que o edit tool envia, o efeito é **falso-deny** (fail-closed) e o smoke acusa — corrigir o padrão antes do merge.
- **`bash` fora do gate.** Resíduo declarado na decisão 1; proibição no prompt + supervisão humana; o smoke só promete o gate dos file tools.
- **Lixo de smoke no PR.** Limpeza explícita antes de `git status`/commit; diff final só com os arquivos da entrega.
- **Prettier vermelho em `.opencode/`.** Rodar `prettier --write` nos tocados; frontmatter com description longa passa como o precedente.
- **Sem hot reload.** Qualquer prova de agente é subprocesso novo (`opencode run`), nunca a sessão atual.
## Aceite de engenharia
- [ ] Aceite de produto da intenção coberto: os dois agentes existem e são invocáveis com os literais pinados; doutrina viva `ui-design-html.md` como fonte de verdade; ladder documentada com tier registrado e `DEGRADED` sem certificação; pré-requisito verificado.
- [ ] Invariantes AGENTS/engineering-standards: sem tocar `src/`; sem migration (`push: false` irrelevante — nada de schema); dono editado (doutrina renomeada, sem twin); precedentes reusados (`designer-campanha-solla.md`, `agent.<nome>.permission` do `opencode.json`); identificadores de código em inglês e texto de prompt/admin em pt-BR.
- [ ] Testes de domínio (unit/int): N/A justificado — nenhum access/write path de app muda; a prova é o smoke de permissão (evidência no PR), e guard/teste novo lendo `.opencode/agent/*.md` está explicitamente fora de escopo.
---
Self-score decision-quality: 5/5 — (1) as 5 decisões caras têm opções e rejeitadas registradas (gate fail-closed, `git mv`, doutrina-fonte-única, ladder/tier, AGENT-OPS); (2) cabe no appetite herdado: 4 arquivos + changelog, sem código e sem `src/`; (3) rabbit holes nomeados (twin de agente, `src/`, consumidores OPS114/OPS116, sandbox de bash); (4) depth check: edita o dono da doutrina (rename, sem par), reusa o precedente de frontmatter/visão e o precedente de `permission` por agente — nenhum módulo, helper ou arquivo extra; (5) o aceite de produto da intenção permanece intacto — a engenharia só escolheu a forma (allowlist, prompts enxutos, onde o tier é registrado).